开发文档

鲜花交易系统与鲜花交易平台(PHP / ThinkPHP 版)的研发记录:功能上线、架构演进与实施经验,按发布日期持续更新。

数据库迁移要留台账:checksum、批次与 baseline

没有台账时的三种混乱

项目前期迁移脚本是纯手动的:sql/migrations/ 目录下按日期命名,人工按顺序执行。脚本攒到 40 多个时,问题集中出现:

  • 不知道跑了哪些:客户现场报错,第一句是"你执行到哪一条了",没人答得上来;
  • 重复执行:两个同事先后跑同一批脚本,第二条就报"表已存在",之后靠人肉跳过;
  • 改了历史脚本:有人为了修一个小问题,直接改了上周的脚本,导致新环境和老环境结构不一致。

这三个问题的共同点是:缺少"执行过什么"的事实记录。

台账表:每一行是一条历史事实

迁移台账表只做一件事:记录每个脚本什么时候执行、执行结果如何、内容有没有被改过。

字段作用
版本/文件名唯一标识一条迁移
校验和(SHA-256)记录执行时文件内容的指纹
批次同一次执行的所有脚本属于同一批,便于回滚定位
耗时排查慢迁移
状态 / 错误摘要成功或失败,失败保留原因

校验和是台账最重要的设计:命令在每次执行前比对"文件当前指纹"与"台账里记录的指纹",不一致就直接拒绝继续。

这条规则拦住的是最常见的一类事故:有人修改了一个已经在客户环境执行过的脚本。结构会悄悄分叉,而且不报错。

命令的三个动作

```

--dry-run 只列出待执行清单,不改库

--status 查看已应用/待执行/校验和不一致

--baseline 存量库首次接入:把已有脚本标记为"已应用"而不真正执行

```

--baseline 解决的是一个很实际的场景:客户库里已经有完整结构(可能是早期人工建的),此时如果直接跑全部迁移,第一条建表就会失败。baseline 的作用是"承认现状,从今天开始记账"。

规范里写得很明确:存量库首次接入必须先 baseline,否则会从第一条重跑。

单个脚本失败就停

执行策略是"顺序执行,遇错即停":

  • 当前脚本在事务里执行,失败则回滚并写状态与错误摘要;
  • 后续脚本不再执行;
  • 修复后重跑,会从这条失败脚本继续(因为它的状态不是"已应用")。

比"跳过失败继续跑"更好的原因很简单:迁移之间通常有依赖(先建表再改列),跳过会造成更隐蔽的结构错误。

文件切分规则要与建库脚本一致

迁移文件里可以有多条语句,切分规则必须与建库导入器完全一致(跳过注释与空行、按行尾分号提交)。

我们在这里错过一次:导入器按"行尾分号"切分,迁移命令按"整行只有分号"切分,结果某些写成一行多语句的脚本,在两条路径下行为不同。统一规则后,这类问题消失。

一条纪律

已应用的迁移文件不得再修改。 需要修正就新增一条迁移。

这条纪律听起来苛刻,但它是"客户环境可复现"的唯一保障。一旦允许改历史脚本,任何两个环境都可能不一样,而你不知道差在哪。

本文属于「开发文档」系列,记录鲜花交易系统(PHP + ThinkPHP 8 + MySQL 8)的实际研发进展。想了解功能清单与报价,可前往系统报价或联系我们。