thinkphp 6.x 读写分离需手动触发才生效:默认所有 select 走主库;配了 read_host 仅注册从库信息,须显式调用 usereadconnection()、read(true) 或 connect('mysql', ['read'=>true]) 才切从库,事务中强制走主库且不报错。

ThinkPHP 读写分离不是靠配置开关自动生效的,而是依赖数据库连接驱动的 switchSql 逻辑和 read_master 行为控制;不手动触发读操作走从库,哪怕配了从库也全走主库。
为什么配了 read_host 却始终不走从库?
ThinkPHP(6.x)的读写分离是“惰性识别”:只有显式调用 db()->read(true)、Db::connect('read') 或在查询方法中传 ['master' => false],才会尝试切换到从库。默认所有 select 都走主库,不会自动分流。
-
read_host只是注册从库连接信息,不等于启用读写分离 - 模型的
where()->find()、select()默认都走主库,除非你加->useReadConnection() - 事务内所有操作强制走主库,
startTrans()后无法切到从库
Db::connect() 和 db() 的读库调用区别
两者底层都用 ConnectionManager,但行为策略不同:
-
db('read'):直接使用名为read的预设连接(需在database.php中定义'connections.read'),不参与读写分离调度 -
Db::connect('mysql', ['read' => true]):触发读写分离逻辑,会按权重轮询read_host列表,支持故障转移 - 更推荐用
Db::name('user')->where(...)->useReadConnection()->find(),语义清晰且兼容链式调用
从库连接失败时怎么避免报错中断?
ThinkPHP 默认从库不可用就抛 ConnectionException,生产环境必须降级处理:
- 在
database.php的从库配置里加'break_reconnect' => false(TP6.1+) - 配合
'read_weight' => [1, 0]把某个从库权重设为 0,可临时下线而不删配置 - 若用自定义
ReadStrategy,注意重写getReadConnection()时 catch 异常后 fallback 到主库,否则整个请求崩掉
事务 + 读操作混合时的陷阱
这是最容易翻车的场景:一旦开启事务,后续所有查询(包括 ->useReadConnection())都会被强制路由回主库,且不会报错提示。
- 原因:事务上下文绑定主库连接对象,
Connection实例不可替换 - 如果业务需要“事务中查从库做校验”,只能拆成两个独立连接:
Db::connect('mysql')->startTrans()+Db::connect('mysql', ['read'=>true])->table(...)->find() - 注意:两个连接之间无事务隔离,不能用于强一致性校验
真正难的不是配参数,而是厘清「谁在什么时候决定走哪条连接」——Query 对象初始化、Connection 获取时机、事务状态标记,这三者嵌套起来,一个 ->cache(true) 都可能绕过你的读库意图。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











