thinkphp 6.0 中事务内所有数据库操作强制走主库——开启事务后,select、find()等查询均自动绑定主库连接,无视slave()调用;前提需正确配置'deploy'=>1和'rw_separate'=>true于数据库连接项内。

ThinkPHP 6.0 中,事务内所有数据库操作默认且必须走主库——这不是可选行为,而是框架底层强制保障的一致性机制。只要开启事务,无论执行的是 SELECT 还是带条件的 find(),TP6 都会自动将整个事务上下文绑定到主库连接,无需额外配置或手动干预。
事务自动绑定主库是硬规则
TP6 的读写分离逻辑在事务开始时即被绕过:一旦调用 Db::transaction() 或使用 @Transactional 注解(配合 ThinkORM 或第三方集成),框架内部会检测 inTransaction() === true,并立即锁定当前连接为 write 配置所指向的主库实例。这意味着:
- 事务中的任何查询(包括
select()、find()、count())都绝不会发往从库; - 即使你写了
Db::name('user')->slave()->select(),在事务中也会被忽略,仍走主库; - 事务提交或回滚后,后续非事务查询才恢复按
rw_separate规则路由。
配置必须启用 deploy 和 rw_separate
事务能正确绑定主库的前提,是读写分离基础配置已生效。若事务里仍意外走到从库,大概率是主从开关未打开:
-
缺一不可:
'deploy' => 1是总闸门,'rw_separate' => true是路由策略,两者必须同时存在且值正确; -
配置位置要对:这两个键必须放在具体连接配置(如
'mysql')内部,不是写在顶层default或全局配置里; -
read 必须是二维数组,例如
['read' => [['host' => '192.168.1.11'], ['host' => '192.168.1.12']]],写成一维会被静默忽略。
锁语句和事务外强一致读也得走主库
除了事务本身,以下两类操作同样强制主库,它们与事务共同构成“一致性兜底链”:
-
显式加锁查询:如
->lock(true)、->where(...)->forUpdate()->find()或原生 SQL 含FOR UPDATE/LOCK IN SHARE MODE; -
主动声明主库:用
->master(true)可绕过所有自动路由,适用于事务外但需强一致的场景(如支付结果查单); -
注意边界:不要在事务中混用
Db::connect('slave'),这会破坏事务隔离,导致从库报错或数据不一致。
主从延迟无法靠框架解决,业务层要兜底
TP6 能保证事务内读写同库,但无法消除主从同步延迟本身。如果业务存在“写完立刻读”的强依赖(比如注册后马上查用户信息),仅靠事务不够:
- 注册操作单独走事务(确保写入+初查都在主库);
- 后续非事务读取(如个人中心展示)若要求实时,应搭配
->master(true)显式指定; - 更优方案是结合缓存标记或短时等待(如写后 sleep(100ms)),但需权衡吞吐与一致性。











