Doctrine迁移报错2002是因CLI无法解析DATABASE_URL中的容器主机名,需改用host.docker.internal或容器内执行;迁移类不可依赖服务容器,须纯PHP操作;状态不一致时应检查doctrine_migration_versions表并人工修复。

doctrine:migrations:execute 报 SQLSTATE[HY000] [2002] 错误
这不是迁移脚本本身有问题,而是执行时根本连不上数据库。常见于 Docker 环境下本地 CLI 执行迁移(比如 php bin/console doctrine:migrations:execute),此时 DATABASE_URL 里的主机名(如 database)在宿主机上无法解析。
检查当前生效的 DATABASE_URL:php bin/console debug:container --env-var=DATABASE_URL。若显示 mysql://...@database:3306/...,就确认是这个问题。
- 开发机直连:把
.env或.env.local中的DATABASE_URL改成mysql://root:root@host.docker.internal:3306/app(macOS/Windows Docker Desktop 可用;Linux 需手动加--add-host=host.docker.internal:host-gateway到docker-compose.yml的 app 服务) - 容器内执行:改用
docker-compose run --rm app php bin/console doctrine:migrations:execute ...,确保运行环境和应用一致 - 别忽略
APP_ENV:迁移默认走dev环境,若你在test或prod下跑,要显式加--env=prod,否则可能读错配置
迁移类中引用了未定义的服务或参数
Symfony 迁移类(Version*.php)在执行时处于容器编译前阶段,不能直接依赖注入服务,也不能用 $this->getParameter() 或 $this->get('some.service') —— 这会直接报 Call to a member function getParameter() on null 或类似 fatal error。
迁移逻辑必须保持“纯 PHP”:只用原生 PDO、硬编码参数,或通过 $schema 和 $queries 操作结构。
- 需要动态值?从
$connection->getParams()里取,比如$connection->getParams()['dbname'] - 想复用业务逻辑?不行。迁移不是控制器,不能调服务。把共用逻辑抽成独立 PHP 类(不依赖容器),再
require_once引入 - 注意命名空间:迁移类必须在
src/Migrations下,且命名空间为DoctrineMigrations,否则 Doctrine 找不到
doctrine:migrations:migrate 卡住或提示 “No migrations to execute”
这通常不是失败,而是状态错位:Doctrine 认为你已执行过该版本,但实际没生效,或者反之。
先看当前状态:php bin/console doctrine:migrations:status。重点关注 Executed Migrations 和 Available Migrations 两栏是否对得上。
- 有迁移显示
up但 DB 表没变?可能是 migration 类里up()方法没写实际 SQL,或用了$schema->createTable()却忘了$schema->save()(新版 Doctrine 不需要 save,但老版本或自定义驱动可能仍需) - 新 migration 显示
not migrated却执行不了?检查文件名是否符合VersionYYYYMMDDHHIISS.php格式,且时间戳严格递增;中间跳号会导致跳过 - 强行同步状态?慎用
php bin/console doctrine:migrations:version --add <version>,它只改doctrine_migration_versions表,不执行任何 SQL
迁移执行中途失败导致数据库状态不一致
这是最危险的情况:部分 SQL 成功,部分失败,doctrine_migration_versions 表没写入,下次再跑会重复执行已成功部分,大概率报错(如 “table already exists”)。
Doctrine 默认不开启事务包裹整个迁移(尤其涉及 DDL 时,MySQL 会隐式提交),所以无法靠 rollback 回滚全部。
- 人工介入:先查
doctrine_migration_versions表确认哪些版本标记为 executed;再对比 DB 实际结构,手工补全或回退缺失/多余操作 - 预防手段:在
up()里拆细粒度,每个原子操作后加if (! $schema->hasTable(...)) { ... }类型防护;生产环境迁移务必先在副本库上完整演练 - 别依赖
--write-sql:它只生成语句,不处理 PHP 逻辑(如数据迁移),不能代替真实执行


















