yii的migrate是数据库结构版本快照系统,非sql快捷方式;改错后不清理记录会触发“the migration history is corrupted”错误。

直接说结论:Yii 的 migrate 不是“执行 SQL 的快捷方式”,而是数据库结构的版本快照系统——改错一次、手动修文件、不清理记录,就会触发 The migration history is corrupted. 这类错误。
创建迁移文件时名字和路径怎么定
运行 yii migrate/create add_status_to_post 后,文件生成在 @app/migrations/(基础模板)或 common/migrations/db/(starter-kit),文件名形如 m240417_235601_add_status_to_post.php。注意三点:
- 前缀
m+ 时间戳(年月日_时分秒)是硬编码规则,不能手改时间部分,否则 Yii 找不到执行顺序 - 文件名里不能有大写字母或空格,Windows 下容易因大小写敏感导致类加载失败
- 多人协作时,若两人几乎同时创建迁移,时间戳可能只差毫秒;Yii 按字典序排序执行,所以必须用
depends显式声明依赖,不能靠提交先后
up() 和 down() 为什么不能随便写 SQL
常见错误是在 up() 里直接写 $this->execute('ALTER TABLE user ADD COLUMN status TINYINT'),然后上线后发现字段加错了,又去改这个文件再跑——这不会生效,因为迁移记录已写入 migration 表,Yii 不会重放已标记为“已完成”的迁移。
- 正确做法是:建表前加
IF NOT EXISTS判断,删字段前先查SHOW COLUMNS FROM user LIKE 'status',保证幂等 - 生产环境严禁在
down()里写dropTable()或dropColumn(),MySQL 大表锁表重建会导致停服 - 外键必须显式处理:
addForeignKey()要配对dropForeignKey(),且dropTable()前必须先删外键,否则报错
safeUp() 和 safeDown() 是什么,什么时候必须用
safeUp() 和 safeDown() 是事务封装版,所有操作包裹在 beginTransaction() / commit() 中。一旦中间某步失败(比如字段类型冲突、索引名重复),整个迁移自动回滚,不会留下半截脏数据。
- 只要涉及多条 DDL(如建表 + 加索引 + 加外键),就必须用
safeUp(),否则出错后得手动 cleanup - MySQL 5.7+ 和 PostgreSQL 支持 DDL 事务,但 SQLite 不支持;用
safeUp()可以提前暴露不兼容问题 - 注意:
safeUp()不等于“绝对安全”——它不校验字段是否被其他代码引用,也不阻止你写dropColumn()这种高危操作
线上执行迁移最危险的三个动作
不是所有 yii migrate/up 都能上生产。以下操作在线上等同于停机维护,必须提前评估并安排窗口期:
-
ALTER TABLE ... DROP COLUMN:MySQL 会重建整张表,500 万行以上基本不可接受 -
ALTER TABLE ... MODIFY COLUMN类型变更(如VARCHAR(255)→TEXT)同样锁表 -
yii migrate/up 100这种批量执行:跳过中间依赖、忽略版本冲突、无法审计每一步,CI/CD 流水线里应禁用
真正该上生产的,只有明确指定版本号的单步执行,例如 yii migrate/up m240417_235601_add_status_to_post,且必须搭配 --interactive=0 关闭交互(避免卡在 stdin)。











