迁移文件必须带YYYYMMDDHHIISS时间戳前缀,否则会被跳过;执行顺序由数据库migration表version字段决定,而非文件名顺序;务必用php think migrate:create生成文件,禁用migrate:refresh/reset生产环境。

迁移文件命名必须带时间戳前缀
ThinkPHP 的 php think migrate:run 不依赖文件名顺序,而是靠数据库表 migration 里的 version 字段排序执行。但如果你手动增删迁移文件、或在多环境同步时没统一命名规则,很容易出现「本地已执行、测试环境报重复创建表」这类问题。
真正起作用的是文件名开头的 YYYYMMDDHHIISS 时间戳(如 20240512142301_create_user_table.php),它会被自动提取为 version 值写入数据库。不带时间戳的文件(比如叫 add_status_to_order.php)会被跳过,且不会报错——这是最隐蔽的坑。
- 生成迁移务必用命令:
php think migrate:create CreateUserTable,别手建文件 - 如果要补历史迁移,时间戳不能早于已有记录中最大的
version,否则执行时会跳过 - 多人协作时,建议提交前检查
application/migration/下最新文件的时间戳是否比自己本地系统时间晚 1 秒以上,避免冲突
up() 和 down() 方法里禁止写业务逻辑
迁移不是部署脚本,up() 和 down() 只该做结构变更:建表、加字段、改索引、删列。一旦在里面调用模型、读写业务数据、发 HTTP 请求,就会导致回滚失败、CI 环境执行卡死,甚至污染测试库。
常见错误现象是:本地 php think migrate:rollback 成功,但 CI 流水线跑迁移时抛出 Class 'app\model\User' not found —— 因为迁移执行时可能还没加载模型类,或上下文不完整。
立即学习“PHP免费学习笔记(深入)”;
-
up()中只允许用Db::execute()或Schema::table()等原生 Schema 操作 - 需要初始化默认数据?单独写个命令类,比如
php think seed:init,和迁移解耦 -
down()必须可逆:删字段可以,删表也可以;但把 JSON 字段拆成多个 varchar 后,down()就没法无损合并回去——这种设计本身就该避免
生产环境禁用 migrate:refresh 和 migrate:reset
php think migrate:refresh 本质是先 down 所有再 up 所有,相当于清空整库重来。migrate:reset 更狠,直接 truncate migration 表并删所有结构。这两个命令在生产环境等于主动删库。
真实线上场景下,你不可能靠刷新迁移来回滚一个上线后发现的字段类型错误——这时候应该写新迁移来 changeColumn,而不是倒回三天前的状态。
- CI/CD 流水线里,只允许用
migrate:run和migrate:status - 上线前用
migrate:status检查目标环境缺失哪些迁移,比盲目跑refresh安全十倍 - 如果真遇到迁移卡住(比如某个
up()执行一半失败),手动更新migration表里对应记录的status为0,再重试,别删表
自定义 migration 目录需同步修改 config/migration.php
ThinkPHP 默认从 application/migration/ 加载迁移,但团队常会把它移到 database/migrations/ 以靠近 Laravel 风格。光改路径不改配置,会导致 php think migrate:status 显示 “No migrations found”,而 php think migrate:run 却静默成功——因为后者实际走的是硬编码 fallback 路径。
这个行为差异源于 ThinkPHP 迁移命令的底层实现:状态检查走的是配置驱动,执行却优先尝试 APP_PATH . 'migration/',再 fallback 到 vendor 内置路径。
- 移动目录后,必须修改
config/migration.php中的path项,例如:'path' => APP_PATH . '../database/migrations/', - 注意末尾斜杠不能少,否则拼接类名时会变成
../database/migrations20240512142301_create_user_table.php - 如果用了多应用模式,每个应用的
config/migration.php都得单独配,别只改 common 下的



















