转班转丢数据是教务系统最常见的故障——课时少结转一节、旧班签到记录对不上、转完发现转错班想退回去。读完你能拿到一套"转班单 + 数据快照 + 幂等结转 + 可回滚"的设计,附可直接抄走的表结构与事务写法。迁移过程分几步、每步怎么防重复、出错了怎么退回,本文用两张表和三条规则讲清楚,适合自研教务、学员系统的开发同学参考。
学员从 A 班转到 B 班,看起来是改一个 class_id,实际要保证五类数据一起迁移:
归属:学员当前班次、新班次、原班次历史要能追溯; 课时:剩余课时余额要结转,已消课时保留在原班记录里; 记录:旧班的签到、出勤、成绩等历史记录不能丢; 课表:新班的排课要能看到该学员,旧班课表里要移除; 通知:家长、班主任要知道转班结果。
如果只 UPDATE 学员表的 class_id,后面四项全部失去依据。转班必须是一次"有快照、可回滚"的事务性操作。
先建一张转班单(transfer_order),状态机 PENDING → DONE → REVERSED,用唯一键防止同一单重复执行:
CREATE TABLE transfer_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(32) NOT NULL, -- 转班单号,全局唯一
student_id BIGINT NOT NULL,
from_class_id BIGINT NOT NULL,
to_class_id BIGINT NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'PENDING', -- PENDING/DONE/REVERSED
created_by BIGINT NOT NULL,
created_at DATETIME NOT NULL,
done_at DATETIME,
reversed_at DATETIME,
UNIQUE KEY uk_order_no (order_no),
UNIQUE KEY uk_student_active (student_id, status) -- 同一学员同时只能有一张未完成转班单
);转班以转班单为准,不直接改学员表:先插单,再在单的状态驱动下执行迁移,重复提交同一单号直接幂等返回,不会重复结转。
转班发起流程:校验目标班级存在且当前有名额 → 生成转班单号 → 插入 PENDING 转班单 → 按单执行数据迁移 → 全部成功置 DONE,任一失败整体回滚。
转班单号由"日期 + 机构号 + 流水号"拼成,全局唯一;同一学员同一状态下唯一键兜底,前端连点、接口重试都不会生成第二张单。
转班的课时结转是最容易出错的环节:如果直接在学员账户上"先扣旧班、再加新班",中途失败就会少一节。正确做法是把结转做成流水:
CREATE TABLE transfer_ledger (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
class_id BIGINT NOT NULL,
delta_lessons INT NOT NULL, -- 正=转入,负=转出
reason VARCHAR(16) NOT NULL, -- MOVE_OUT/MOVE_IN
balance_after INT NOT NULL,
UNIQUE KEY uk_order_class (order_id, class_id)
);旧班扣一节(MOVE_OUT)、新班加一节(MOVE_IN)都挂在同一转班单下,uk_order_class 保证同一单对同一班级只结转一次。余额用乐观锁校验"扣减后不为负",结转失败整单回滚,不会出现旧班扣了、新班没加上的中间态。
UPDATE student_lesson
SET balance = balance - #{delta}, version = version + 1
WHERE student_id = #{sid}
AND balance - #{delta} >= 0
AND version = #{v};影响行数为 0 说明余额不足或版本过期,整单回滚并提示教务核对。MOVE_OUT 与 MOVE_IN 放在同一数据库事务内提交,要么都成功,要么都不落。
转班操作与签到、消课可能并发发生:转班到一半,学员在旧班签了个到。处理原则是"先冻结、后迁移":
转班单进入 PENDING 时,锁定学员的消课与签到入口,短暂冻结、秒级完成;迁移完成置 DONE 后立即释放。若冻结期间恰好有已开始的上课记录,按其班级归属处理:属于旧班的保留在旧班,不随迁移走。
冻结窗口要短,避免影响正常上课;用版本号记录学员数据版本,迁移完成后新操作都落在新班,旧版本操作在提交时被拒绝并提示重试。版本号在学员账户与签到记录上各存一列,迁移时取快照版本,迁移完成后所有写操作必须以新版本为前提,旧版本的写请求返回冲突,前端提示刷新后重试。
转班允许撤销(REVERSED),但不是把字段改回去,而是走冲正:
撤销时生成一张反向转班单:新班转出、旧班转入,课时按原结转明细冲正,签到与课表记录按快照回写。原转班单标记 REVERSED,冲正流水挂在撤销单下,两单都留痕可查。
冲正单与原转班单通过 prev_order_id 关联,报表统计课时时只认流水、不认账户余额字段,任何时点的课时都能由流水重算出来。
转班本质是"业务主数据迁移",通用做法是:迁移单承载唯一事实、明细流水记录每步变更、快照保证可追溯、冲正支持回滚。这套思路同样适用于学员换校区、班级合并、课程版本升级等迁移场景。先梳理清楚要迁移的数据清单,再按"单—流水—快照"三层建模,比在业务代码里补丁式改字段可靠得多。本文方案仅作技术分享,具体实现按自身业务取舍。
Q:学员中途转班,课时和上课记录怎么跟着走?
A:以转班单为唯一事实,课时按转出转入流水结转并幂等去重,旧班签到与成绩保留在原班,新班课表同步加入,撤销走冲正单回滚。
Q:转班时课时余额怎么算才准?
A:旧班按已消课记录计算剩余,转出记负流水;新班转入记正流水,同一转班单对同一班级只结转一次,余额乐观锁校验不为负。
Q:转班操作和签到同时发生怎么办?
A:转班单进入待处理时短暂冻结该学员的消课与签到入口,迁移完成后释放;冻结前已开始的上课记录按原班级归属保留。
Q:转错班了能退回吗?
A:可以。生成反向转班单,课时按原结转明细冲正,课表与签到记录按快照回写,原单标记撤销,全程留痕可查。
Q:转班后旧班的课还上吗?
A:转班完成后学员只出现在新班课表,旧班课表同步移除;迁移前旧班已发生的课时按旧班记录保留,不做回退。
转班数据丢失的根因,是"改字段"代替了"事务性迁移"。用转班单、明细流水和冲正把迁移做成可追溯的操作,数据自然不丢。仅作技术分享。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。