symfony需手动配置doctrine多连接并实现读写路由:在doctrine.yaml中定义master/slave连接且server_version一致,注入独立connection实例,select优先走slave但事务、强一致性场景必须用master,并处理主从延迟与从库故障。

Symfony 本身不原生支持读写分离,必须靠 Doctrine DBAL 手动配置多连接 + 自定义路由逻辑,否则所有查询都会走默认连接。
Doctrine 配置多个连接(master/slave)
在 config/packages/doctrine.yaml 中不能只写一个 default_connection,必须显式定义多个连接,并禁用自动默认绑定:
- 删掉或注释掉
default_connection: default这类全局绑定 - 用
connections键列出至少两个连接,比如master和slave - 每个连接需完整声明
url(或host/port/user等),且server_version必须一致,否则 DBAL 可能报 schema 不兼容 - 从库连接建议加
replica: true标记(非必需但利于后续识别)
示例片段:
doctrine:
dbal:
connections:
master:
url: '%env(DATABASE_URL_MASTER)%'
server_version: '8.0'
slave:
url: '%env(DATABASE_URL_SLAVE)%'
server_version: '8.0'
replica: true
手动实现读写路由逻辑
Doctrine 没有 Laravel 那样的 read/write 数组自动路由机制,你得自己判断 SQL 类型并选连接。常见错误是:在 Repository 或 Service 里硬编码 $this->connection->executeStatement(),结果永远只走默认连接。
- 不要依赖
doctrine.dbal.default_connection,它只会返回一个连接 - 推荐做法:注入多个
Connection实例(如doctrine.dbal.master_connection和doctrine.dbal.slave_connection),由业务代码决定用哪个 - 对
SELECT类查询,优先用slave;但涉及JOIN、UNION、子查询或需要强一致性的场景(如刚写完立刻读),必须切回master - 事务内所有操作(包括
SELECT)必须强制走master,否则会报错或读到过期数据
事务与主从延迟的兜底处理
读写分离最常被忽略的是「刚写完就读不到」问题——因为主从同步有延迟。这不是配置错误,而是架构必然代价。
- 不能指望框架自动识别“这个 SELECT 是不是该等同步”,得靠业务层控制:例如用户提交表单后跳转详情页,详情查询必须走
master - 可封装一个
StrongConsistencyConnection装饰器,在关键路径显式调用$conn->fetchAssociative("SELECT ...")前先确认是否在事务中或是否标记为强一致 - 从库连接失败时,
slave连接抛异常,别静默 fallback 到master—— 否则会掩盖故障;应捕获ConnectionException并按需降级或告警
真正难的不是配出两个连接,而是让每个 SELECT 都经过一次「这里能不能走从库」的判断。漏掉一次,就可能在线上出现用户看不到自己刚提交的数据。











