执行迁移前必须确认数据库配置生效,.env中database_url需指向可写目标库且用户具备create、alter权限,避免因配置未切换导致driverexception错误。

执行迁移前必须确认数据库配置是否生效
迁移命令不会自动读取环境变量或覆盖配置,.env 中的 DATABASE_URL 必须指向可写入的目标库,且用户有 CREATE、ALTER 权限。常见错误是本地用 sqlite:///%kernel.project_dir%/var/data.db,但部署时忘了切到 MySQL 配置,结果 php bin/console doctrine:migrations:migrate 报错 DriverException: An exception occurred in driver: could not find database file。
- 运行
php bin/console doctrine:database:create --if-not-exists验证连接通不通 - 检查
config/packages/doctrine.yaml中doctrine.dbal.url是否被硬编码覆盖 - 生产环境务必加
--env=prod,否则可能误用dev的缓存或日志配置
生成新迁移文件时要避免空迁移
php bin/console doctrine:migrations:generate 会扫描实体变更并生成 SQL,但它只对比当前 doctrine:schema:update --dump-sql 输出和已应用的迁移版本。如果实体没改、或 mapping 配置漏了 App\Entity\*,就会生成一个空的 VersionXXXXXX.php,里面只有 up() 和 down() 的空函数体——这种文件不能删,但也不能直接跑,否则 migrate 会跳过它,下次再改实体又生成新的空迁移。
- 生成后立刻打开文件,确认
$this->addSql(...)语句存在且非空 - 若为空,先运行
php bin/console doctrine:schema:update --dump-sql看是否有预期 SQL,没有就检查实体注解或 YAML mapping 是否加载成功 - 不要手动编辑生成的
Version*.php文件中的 SQL,应删掉重生成,否则版本哈希校验失败
上线时迁移必须带 --no-interaction 和 --allow-no-migration
CI/CD 流水线里执行 php bin/console doctrine:migrations:migrate 默认会交互式询问“是否继续”,卡住整个部署。更麻烦的是,如果当前数据库已是最新版本,命令默认退出码为 1(失败),导致部署中断——但其实这是正常状态。
- 始终加上
--no-interaction关闭提示 - 加上
--allow-no-migration让无新迁移时返回 0(成功) - 生产环境建议加
--timeout=300防止大表锁表超时被 kill - 别在迁移中执行耗时 PHP 逻辑(比如循环更新百万行),应拆成独立命令或后台任务
回滚迁移的风险比想象中高
php bin/console doctrine:migrations:rollback 只能退一步,且依赖 down() 方法实现。但 Doctrine 不自动生成安全的逆向 SQL:比如 ADD COLUMN 的 down() 是 DROP COLUMN,但如果该列已有数据,MySQL 8+ 会拒绝执行;又比如 CHANGE TABLE engine=InnoDB 的逆向操作在 down() 里写成 engine=MyISAM,而新版 MySQL 已弃用 MyISAM。
- 回滚前务必在同结构的测试库上完整跑一遍
down() - 涉及数据迁移(如
INSERT INTO ... SELECT)的up(),down()必须显式清理,不能只靠DROP TABLE - 线上严禁对已发布版本做
rollback,应通过新增迁移来修复,保持版本线性
迁移不是魔法,它只保证 SQL 执行顺序,不保证业务一致性。哪怕所有命令都绿了,也得查 doctrine_migrations 表确认 executed_at 时间戳和你的部署时间吻合,否则可能是缓存或权限问题导致假成功。











