doctrine.yaml 必须严格分层配置dbal连接与orm映射,缺一不可;多连接需手动定义default/replica;缓存需元数据、查询、结果三层对齐;proxy_dir须可写且路径合法,prod环境禁用auto_generate_proxy_classes。

直接说结论:doctrine.yaml 不是“设一下就行”的配置文件,它必须按 Doctrine 三层缓存、连接定义、ORM 行为三块逻辑分层写,漏掉任何一层都可能让缓存不生效、读写分离失效或代理类生成失败。
doctrine.yaml 必须声明 dbal + orm 两个顶层键
只写 dbal 或只写 orm 都会报错 —— Doctrine 要求两者共存(哪怕 ORM 暂时不启用)。
-
dbal块负责数据库连接、驱动、URL、连接池、字符集等底层配置 -
orm块控制实体扫描路径、代理类生成、缓存策略、DQL 函数注册等映射层行为 - 缺一不可。例如,删掉
orm后执行php bin/console doctrine:schema:update会提示 “No metadata found”
多连接(如读写分离)必须显式定义两个独立 connection
Symfony 的 doctrine.yaml 不支持 read/write 嵌套语法,Laravel 那套在这里完全无效。
- 你要手动定义
default和replica两个 connection,各自带完整 DSN、host、user、password -
default用于写操作和所有事务内查询;replica只能由业务代码显式获取服务doctrine.dbal.replica_connection后调用 - 不能只改
DATABASE_URL环境变量 ——replica的 DSN 必须在 YAML 里单独写死,且不能复用%env(DATABASE_URL)%变量 - 事务中一旦调用
$em->getConnection()->beginTransaction(),后续所有查询(包括 SELECT)都强制走default,切到replica会抛DriverException
缓存配置必须三层对齐,否则查不到数据或编译失败
Doctrine 缓存不是“开个开关”,而是元数据、查询、结果三者协同工作。少配一层,就等于白配。
-
metadata_cache_driver:推荐pool: doctrine.system_cache_pool(配合 Redis)或pool: doctrine.cache_pool(APCu),不建议用array(仅开发) -
query_cache_driver:必须和元数据缓存用同一 pool 类型,否则 DQL 解析失败时不会 fallback,直接报CacheException -
result_cache_driver:真正存查询结果,需额外配置 TTL(如default_lifetime: 3600),且只有显式调用useResultCache(true, 3600)才生效 - YAML 中若只配了
result_cache_driver但没配前两层,findAll()仍会走 SQL,缓存形同虚设
容易被忽略的硬性限制点
这些不是“建议”,是 Doctrine 运行时强制校验的规则,踩中一个就会中断流程:
-
proxy_dir必须可写,且路径不能含~或未解析的环境变量(如%kernel.project_dir%/var/proxies是安全的,~/var/proxies会报错) -
auto_generate_proxy_classes在 prod 环境必须为false,否则每次请求都尝试生成,导致性能雪崩 - 使用
pool配置连接池时,class必须是Doctrine\DBAL\Pool\ConnectionPool(旧文档写的Doctrine\Common\Pool已废弃,会导致启动失败) - 如果启用了
sticky行为(写后立刻可读),这个逻辑必须由你用RequestStack或Session手动维护 flag,Doctrine 不提供任何钩子











