工程正确性(三):迁移登记、Checksum 与回滚边界
迁移成功不等于数据库已经可用。空库安装验证的是完整历史,线上升级还要考虑旧应用并存、DDL 锁、回填速度和权限。一次服务发布曾在代码和容器准备完成后,生产账号执行迁移却因缺少 ALTER 和 INDEX 权限失败。这个问题不在 SQL 内容,属于迁移前置条件没有进入发布检查。
登记表是事实来源
迁移记录至少包含版本、文件名、checksum、执行序号、状态、执行人、耗时和错误摘要。已执行文件禁止原地修改,修正使用新版本。启动时发现文件 checksum 与登记值不一致,应停止自动迁移并报警,不能为了让部署继续而覆盖登记表。
登记表自身也要受保护。应用账号只读,迁移执行器拥有写入权限。手工 SQL 如果改变了生产结构,要补成正式迁移或登记为已应用版本,不能让测试环境和线上环境依靠“历史操作”维持一致。
Expand、Backfill、Contract
Expand 先添加可空字段、兼容索引或快照表,旧应用继续可用。应用升级后双写旧字段和新字段,后台使用稳定主键游标分批回填历史数据。对账完成后切换读路径,观察窗口结束,所有旧实例和离线任务退出,才进入 Contract。
回填条件带上新字段为空、源版本未变化等保护,防止覆盖在线写入。每批记录起止主键、扫描数、更新数、跳过数、失败数和校验摘要。暂停后从已提交游标继续,批次重试具备幂等条件,不能依赖 offset 扫描变化中的数据。
对账不只比较行数。字段拆分检查空值、范围、唯一性和重组结果,表迁移检查关联完整性,编码转换检查不可映射值。允许差异和处理结果写进发布记录,抽样人工核对只作为补充。
回滚按阶段定义
增加字段通常可以通过应用开关回退,读切换也可以切回旧路径。已经删除列或完成不可逆数据修正时,回滚依赖备份、归档表或补偿迁移,不能承诺“一键恢复”。发布单在执行前写清每个阶段的恢复动作、数据保留时间和负责人。
DDL 是否可事务回滚取决于数据库和语句。长时间索引创建、表重写和锁等待要在接近生产规模的副本上演练。取消后可能留下临时对象或已提交结构,运维手册记录检查命令,值班人员先判断阶段再执行恢复。
权限和环境前置检查
迁移前检查数据库版本、字符集、时区、扩展、连接用户权限和复制延迟。应用账号缺少 ALTER、INDEX 等权限时,部署工具应在执行前失败并给出缺失权限,不能等到半个迁移已完成才报错。需要管理员执行的结构变更和应用执行的数据回填分成两个明确步骤。
空库安装从零执行完整迁移,历史升级从每个受支持版本快照执行,再比较表、列、索引、约束、默认值和字符集。两条路径的目标结构应一致,手工基线脚本也由完整迁移生成并校验。
与业务快照的关系
测评平台引入题目快照时,兼容期允许历史任务缺少快照,回填任务再依据发布包与运行实例补齐 release_id。读取路径切换后,每个响应仍带版本标记,并用旧任务、草稿复制和报告生成三类场景检查引用关系。
发布门禁
CI 至少执行空库安装、受支持版本升级、迁移 checksum 校验、回填中断重启和对账脚本。发布演练保存耗时、锁等待、日志增长、复制延迟和权限检查结果。缺少任何一项证据时,状态应保持未验证,而不是用一次本地成功运行代替。
迁移纪律保证数据库变化可解释、可恢复和可复现,不能消除业务数据异常或数据库自身故障。不可逆操作可以存在,前提是它的边界、备份和恢复时间被明确记录。