thinkphp 5.0–5.1 读写分离需显式配置 'read_master' => true 且仅 select 类查询走从库,受事务和上一条写操作影响;tp6.0+ 改用 deploy + rw_separate,绑定模型操作,支持从库轮询但无健康检测,升级时需注意连接池与事务透传问题。

ThinkPHP 5.0–5.1 的读写分离靠 read_master 控制,但不自动切换
TP5.0 和 5.1 默认不开启读写分离,必须手动配置 read_master 为 true,且仅在执行 select 类查询(如 find、select)时,才尝试从从库读取——前提是主库连接已建立、且从库配置存在。
常见错误是以为设了 'read_master' => true 就万事大吉,结果发现所有读请求仍走主库。这是因为 TP5.0–5.1 的从库选择逻辑非常简单:它只检查当前是否处于事务中(inTransaction()),以及是否刚执行过写操作(靠内部标记 lastInsID 或 lastSql 判断)。一旦上一条 SQL 是 INSERT 或 UPDATE,后续的 select 会强制回主库,避免主从延迟导致查不到刚写入的数据。
-
'read_master' => true必须显式写在数据库配置数组里,不能只靠环境变量覆盖 - 从库列表用
'slave' => ['host' => '192.168.1.10']格式,不支持嵌套数组(如['slave' => [['host' => 's1'], ['host' => 's2']]]) - 没有负载均衡策略,默认轮询,但不会跳过不可用从库——连接失败就直接报错,不 fallback
ThinkPHP 6.0+ 改用 deploy + rw_separate,支持更细粒度控制
TP6.0 彻底重构了数据库配置结构,用 deploy(部署模式)替代 read_master,并引入 rw_separate(读写分离开关)和 master_num(主库数量)等新键。最关键的是:读写分离行为现在与「模型操作」强绑定,而不是仅靠 SQL 类型判断。
例如,调用 UserModel::where('id', 1)->find() 会走从库;但 UserModel::where('id', 1)->value('name') 却可能走主库——因为 value 底层用了 query 方法,而 TP6 对 query 的路由逻辑和 select 不一致。这种差异容易被忽略,导致部分读接口没真正分到从库。
-
'deploy' => 1是启用读写分离的前提,单独设'rw_separate' => true无效 - 从库配置必须是二维数组:
'slave' => [['host' => 's1'], ['host' => 's2']],一维会静默失败 - TP6.3+ 开始支持
'slave_balance' => 'random',但默认仍是'round'(轮询),且无健康检测
TP5.1 升级到 TP6.x 时最常踩的坑:从库连接复用与事务穿透
TP5.1 中,从库连接是“即用即连、用完即关”,不会复用;而 TP6.x 默认开启连接池,并对主从连接分别缓存。这导致两个问题:一是高并发下从库连接数暴涨(因每个请求都新建从库连接,池未生效);二是事务中执行 select 时,TP6 会把事务上下文透传给从库连接——但 MySQL 从库不支持写事务,结果报错 Can't execute the given command because you have an active transaction。
- 必须在从库配置中显式关闭事务支持:
'slave' => [['host' => 's1', 'params' => [\PDO::ATTR_AUTOCOMMIT => 1]]] - 若用
Db::transaction()包裹读写混合操作,所有语句都会强制走主库,rw_separate失效 - TP6 的
Db::connect('slave')返回的是连接实例,不是配置别名,不能直接用于模型指定
TP6.3+ 的 read_time_out 和 slave_failover 仍属半成品功能
官方文档提到 read_time_out 可设置从库读超时后 fallback 主库,但实际测试发现:该参数只影响 PDO 连接建立阶段,不控制查询执行超时;而 slave_failover 设为 true 后,某个从库宕机时,TP6.3 并不会自动剔除它,而是每次轮询都重试,直到全部从库失败才切主库——中间产生大量 PDOException: SQLSTATE[HY000] [2002] Connection refused。
真正在生产环境可用的容灾方案,还是得靠外部手段:比如用 HAProxy 做从库健康检查和流量转发,或在配置中预设多个从库并配合自定义连接工厂,在 connect 方法里做 try-catch + 降级逻辑。
读写分离从来不是开个开关就能稳的。配置项变来变去只是表象,核心永远是:你能否感知主从延迟、能否容忍脏读、以及有没有能力在从库失联时不让整个读接口雪崩。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











