ThinkPHP 6.0 读写分离不保证事务一致性,仅做连接路由;事务期间所有操作强制走主库,需开发者主动控制。

ThinkPHP 6.0 的读写分离本身不保证事务一致性,它只做连接路由,而事务一致性必须靠开发者主动控制——这不是配置问题,而是架构逻辑问题。
事务期间所有操作强制走主库
TP6 明确规定:一旦调用 Db::startTrans() 或进入 Db::transaction() 闭包,后续所有查询(包括 select()、find())都会自动回落主库。这是防止从库读到未提交数据的硬性安全策略。
- 无需额外配置,只要事务开启,读写分离自动失效
- 若在事务中调用
Db::name('user')->select()却查不到刚插入的数据,说明你误以为它走了从库——实际已强制切回主库,问题出在其他环节(如异常未穿透、引擎非 InnoDB) - 跨模型或混用
Db::connect()会破坏事务上下文,导致部分操作脱离主库连接,必须统一使用默认连接实例
刚写完立刻要读?不能依赖读写分离
主从延迟下,“写完马上读”天然不可靠。TP6 不提供延迟检测、强一致性读开关或自动 fallback 机制。
- 业务有“写后即读”需求时,必须显式走主库:
Db::master()->table('user')->where('id', $id)->find() - 不要依赖
useReadConnection()或等待同步,延迟可能达数百毫秒甚至更久 - 高频场景可考虑缓存兜底(如 Redis + 主键预写),而非强求数据库实时
配置错误会导致事务“看似生效实则失效”
读写分离配置不全,会让所有查询静默走主库——表面看事务正常,实则丧失从库分流能力,且掩盖了真正的问题根源。
立即学习“PHP免费学习笔记(深入)”;
- 四个条件缺一不可:
'deploy' => 1(整型)、'rw_separate' => true、'read'是二维数组、'write'是单维数组 -
'read'写成['hostname' => '...'](一维)→ 框架不报错,但所有select()都走主库,事务里也一样,你以为是机制问题,其实是配置失效 -
'write'写成二维数组 → 直接抛出Invalid write database config,事务根本无法启动
事务回滚失败?往往和读写分离无关,但容易混淆
回滚失效的常见原因集中在底层环境与代码结构,而非读写分离本身:
- 表引擎不是 InnoDB(MyISAM 不支持事务)
- 事务闭包内异常被
try-catch吞掉且未重抛 - 调试时用了
dd()或exit,导致 PDO 连接卡在 active 状态,后续请求复用该连接时事务异常 - 混用不同连接(如
UserModel::create()和Db::connect('slave')->insert()),后者不在事务作用域内



















