ThinkPHP 6 读写分离需同时满足 deploy => 1、rw_separate => true,且 read 必须为数组套数组、write 为单数组,否则默认全走主库;查询带锁、在事务中或调用 ->master() 时强制走主库。
ThinkPHP 6 的读写分离不是“配了 read 就自动走从库”,必须同时满足
、
,且
和
配置结构正确,否则全走
连接——也就是主库。
database.
php
里怎么写才算真正启用读写分离
很多人把
写成单个数组(比如
),结果 TP 启动就报错或静默失效。TP6 要求
必须是「数组套数组」,哪怕只配一个从库也要写成
;
只能是单个完整连接数组,不能是数组套数组,否则直接抛出
。
关键点在于:整个读写分离逻辑由
下的配置驱动,而
只是用来指向这个配置名:
设为
(字符串)
下必须包含:
、
、
、
漏掉
,整个读写分离模块根本不会初始化
为什么 Db::name('user')->select() 还是走主库
TP6 不是按 SQL 类型(如是否含 SELECT)判断路由,而是按方法语义 + 上下文联合判定。以下情况会强制走主库:
立即学习
“
PHP免费学习笔记(深入)
”;
查询带锁:
或原生 SQL 含
/
当前处于事务中:
后的所有查询,无论是否只读,全部回落到主库
调用了写操作连贯方法(如
),TP 有时会误判为写意图
纯读方法(
、
、
、
)才可能进从库,前提是没触发上述任一条件。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
Db::connect() 和 Db::name() 对读写分离的影响
完全依赖
所指向的连接配置(即
)是否开启
;而
是创建全新连接实例,它只认自己配置里的
,完全不参与
/
路由逻辑。
也就是说:
想用读写分离 → 必须走
(或
)+ 正确的
配置
用了
→ 等于手动绕过读写分离机制,该连接永远只连指定地址
临时切从库又不想改全局?只能通过
动态重设,没有
这种链式方法
从库延迟时业务层怎么兜底
TP6 不做延迟探测、不自动故障转移、不支持权重轮询——它只是随机选一个
数组元素去连。一旦从库同步滞后,
后立刻
可能查不到数据,这是框架明确声明的「需业务层兜底」场景。
常见应对方式:
强一致性读:对刚写入就查的场景,显式加
,例如
缓存兜底:写后更新 Redis 缓存,读优先走缓存,避免直击从库
延迟容忍提示:前端展示「数据同步中」状态,配合定时轮询
别指望 TP 自动识别主从延迟并切换连接——它连
都不执行。
deploy => 1rw_separate => truereadwritedefaultread['hostname' => '192.168.1.10']read[0 => ['hostname' => '192.168.1.10']]writeInvalid write database configconnections.mysqldefaultdefault'mysql'connections.mysql'deploy' => 1'rw_separate' => true'read' => [[...]]'write' => [...]deploy => 1->lock(true)FOR UPDATELOCK IN SHARE MODEDb::startTrans()->order()->limit()->count()find()select()value()column()Db::name('user')defaultconnections.mysqlrw_separateDb::connect('xxx')hostnamereadwriteDb::name()Db::table()connections.mysqlDb::connect('slave1')Db::$connection->config(['read' => [...]])->slave()readsave()find()->master()Db::name('user')->master()->where('id', $id)->find()SHOW SLAVE STATUS