需在doctrine.yaml的entity_managers块中显式声明多个EntityManager,每个须指定独立connection和mappings;使用时须通过完整service ID(如doctrine.orm.customer_entity_manager)注入,并在CLI命令中加--em=xxx参数指定管理器。

怎么配多个 entityManager?看 doctrine.yaml 的 entity_managers 块
Symfony 默认只配一个 default EntityManager,要加第二个,不能靠复制粘贴整个 Doctrine 配置,得在 doctrine.yaml 里显式声明 entity_managers 块,并为每个 manager 指定独立的 connection 和 mappings。
常见错误是只加了新 connection,但没在 entity_managers 下定义对应 manager,结果 php bin/console doctrine:database:create 或 doctrine:schema:update 完全不认它。
-
entity_managers下每个 key 是 manager 名(如customer),不是连接名 - 每个 manager 必须指定
connection(对应connections下的 key),否则启动报错:The service "doctrine.orm.customer_entity_manager" has a dependency on a non-existent service "doctrine.dbal.customer_connection" -
mappings要单独配,别复用默认的;否则两个 manager 会同时加载同一组实体,触发MappingException: Duplicate class
doctrine:
dbal:
connections:
default: {...}
customer: {...}
orm:
entity_managers:
default:
connection: default
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity\'
customer:
connection: customer
mappings:
Customer:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity/Customer'
prefix: 'App\Entity\Customer\'
用哪个 entityManager?注入时必须带 service ID 后缀
Doctrine 把每个 EntityManager 注册成独立 service,ID 格式是 doctrine.orm.<name>_entity_manager。不写全名,容器根本找不到——别指望自动注入 EntityManagerInterface 就能切库。
典型场景:你有个 CustomerRepository,想让它只走 customer 连接,就不能用默认的 EntityManagerInterface 构造注入。
- 在服务定义里明确写
arguments: ['@doctrine.orm.customer_entity_manager'] - 用 PHP 8 属性注入时,类型必须是具体类名:
private CustomerEntityManager $em;(前提是已定义该类别名)或直接用EntityManagerInterface+#[Autowire(service: 'doctrine.orm.customer_entity_manager')] - 命令行操作(如迁移)也要指定 manager:
php bin/console doctrine:migrations:migrate --em=customer
doctrine:schema:update 为啥只刷 default 库?不加 --em 就默认只动第一个
所有 Doctrine CLI 命令(schema:update、fixtures:load、cache:clear)默认只作用于 default EntityManager。这不是 bug,是设计:避免误操作波及生产库。
现象:你改了 Customer 实体,跑 doctrine:schema:update --force,表没建,日志里连 Customer 字样都不出现。
- 必须显式传
--em=customer,哪怕只有一个非 default manager -
doctrine:schema:validate同样受限制,不加--em只校验 default 的 mapping 和 DB 一致性 - CI 脚本里漏写
--em是高频翻车点,尤其当default库结构稳定、customer库频繁迭代时
事务跨库一定失败?Connection::beginTransaction() 不支持分布式
Symfony+Doctrine 的事务管理天然绑定单个 Connection。你用 customer 和 analytics 两个 EntityManager,在同一个 @Transactional 方法里分别 persist,最后调 $em1->flush() 和 $em2->flush() —— 这看起来像事务,其实只是两个独立事务。
一旦第二个 flush 失败,第一个已经提交,无法回滚。这不是配置问题,是底层 PDO 不支持跨连接事务。
- 别试图用
$em1->getConnection()->beginTransaction()然后手动控制两个连接,PDO 不认这种“外部” begin - 真需要强一致性,得换方案:发消息队列、用 Saga 模式、或者把关键数据冗余到主库做最终一致
- 最容易被忽略的是:开发环境常只连一个库(
default),测试不出跨库事务失效的问题,上线才暴露










