doctrine migrations仅管理schema结构变更,不管理数据版本;安全回滚依赖手动编写的down()方法和transactional: true事务保障,不可自动逆向生成,且须规避truncate、删表、改列类型等不可逆操作。

Doctrine Migrations 本身不管理“数据版本”,只管理数据库 schema(表、字段、索引等结构)的变更;所谓“安全回滚”,本质是靠你手写的 down() 方法 + 事务保障,不是自动逆向生成。
回滚前必须确认 transactional: true
Doctrine 默认开启事务,但老项目或自定义配置中可能被关掉——一旦禁用,down() 执行中途失败,就无法回滚已执行的部分,直接导致数据库状态残缺。
- 检查
config/packages/doctrine_migrations.yaml(Symfony 5+)或app/config/config.yml(Symfony 2)中是否含transactional: true - 若用 PHP 配置(
migrations.php),确认数组里有'all_or_nothing' => true(v3+ 推荐用这个键名) - 运行
php bin/console doctrine:migrations:status后,看输出里是否有Transaction isolation: enabled
down() 方法不能靠 up() 自动推导
你写 up() 添加一个 email 字段,Doctrine 不会帮你生成删字段逻辑;down() 必须显式写:$schema->getTable('user')->dropColumn('email');。漏写或写错,回滚就失效。
- 删除列前,先检查该列是否被其他表外键引用——否则
dropColumn()直接报错 - 修改列类型(如
string(255)→text)在down()中不可逆,应避免;真要改,down()得手动指定长度并用changeColumn() - 清空表(
$this->addSql('TRUNCATE TABLE foo'))无法安全回滚,因 TRUNCATE 不在事务内生效(MySQL),改用 DELETE + WHERE
回滚到特定版本的命令与陷阱
用 doctrine:migrations:migrate 回滚最稳妥,但参数容易误用:它接受版本号或别名,不是文件名。
- 回滚到上一版:
php bin/console doctrine:migrations:migrate prev(注意是prev,不是previous) - 回滚到某具体版本:
php bin/console doctrine:migrations:migrate Version20240307125735(不含 .php,也不带路径) - 别用
doctrine:migrations:rollback——它只执行最新一次迁移的down(),且不校验依赖,易跳过中间版本 - 执行前加
--dry-run:php bin/console doctrine:migrations:migrate prev --dry-run,确认 SQL 是否符合预期
第三方表干扰导致迁移失败
当数据库里混有 WordPress、Shopify 或其他系统表时,doctrine:migrations:diff 可能误读它们为你的实体表,生成错误迁移;回滚时也容易误删。
- 在 Doctrine DBAL 配置中加
schema_filter,例如只处理app_*开头的表:'schema_filter' => '~^app_~' - 该配置需放在数据库连接层(
doctrine.dbal.connections.default.options),不是 migrations 配置里 - 验证是否生效:运行
php bin/console doctrine:schema:list,确认输出里只有你关心的表
真正危险的不是回滚命令本身,而是 down() 里没考虑数据依赖、外键约束、或跨表业务逻辑——这些没法靠工具检测,只能靠人审。











