thinkphp读写分离必须同时满足deploy=1、rw_separate=true、read为二维数组、write为一维数组四条件,缺一则所有读操作静默走主库;deploy必须是整数1,rw_separate必须是布尔true,read每个子数组需含完整连接参数,事务/锁查询强制走主库。

读写分离在 ThinkPHP 中不是“配完就生效”,而是必须同时满足四个硬性条件:`deploy` 开关启用、`rw_separate` 显式为布尔 true、read 是二维数组、write 是一维数组——缺一,所有读操作都会静默回退主库。
为什么配置了 read/write 却仍走主库?
最常见原因是框架根本没触发读写分离逻辑,而不是路由错了。ThinkPHP 6 不会自动扫描配置里的 read 和 write,它只在 deploy === 1 且 rw_separate === true 同时成立时才加载该机制。
-
deploy必须是整数1,写成true或字符串"1"都无效 -
rw_separate必须是布尔true,写成1或"true"会导致静默失败 -
read若写成一维数组(如['hostname' => '192.168.1.11']),框架不报错但直接忽略,所有读操作 fallback 到write -
write若误写为二维(如[['hostname' => 'master']]),启动即抛出Invalid write database config
TP6 标准配置结构怎么写才合法?
ThinkPHP 6 要求主从配置必须嵌套在 connections 的某个连接名下(如 mysql),且所有参数同级存在,不能混用旧版单值配置(如 DB_HOST)。
-
default键必须指向该连接名,例如'default' => 'mysql' -
connections['mysql']内必须包含完整驱动参数:type、hostname、database、username、password、charset—— 漏掉type可能导致 PDO 加载失败 -
write是一维关联数组,含至少hostname、username、password、database;read是二维数组,每个子数组也必须含这四项,不能只写hostname - 所有节点的
charset值必须一致(推荐统一为utf8mb4),否则 emoji 或四字节字符写入/读取异常
哪些查询会被强制发往主库?
ThinkPHP 不解析 SQL 语义,而是靠方法签名和上下文做简单判断。即使配置完全正确,以下情况也会绕过从库:
- 调用
lock(true)或原生 SQL 含FOR UPDATE、LOCK IN SHARE MODE→ 强制主库 - 任何事务内执行的
select()、find()、count()→ 全部走主库,避免主从延迟导致数据不一致 - 显式调用
->master()后未重置,后续查询持续锁定主库 -
Db::query('SELECT ...')默认走主库,除非链式调用->useReadConnection()
主从延迟问题怎么兜底?
ThinkPHP 自身不提供延迟检测或因果一致性开关,所谓“刚写完立刻能读到”必须由业务层控制。
- 注册后跳转个人页查不到新记录?这不是配置错误,而是真实主从延迟。解决方案只有两个:要么在关键路径上手动加
->master(),要么用 MaxScale 等中间件开启causal_reads=local - 若用 MaxScale,TP 配置里反而要关闭
rw_separate,把hostname和hostport指向 MaxScale 监听地址(如192.168.3.102:4006),让协议层完成路由 -
Db::connect('slave1')是绕过读写分离机制的写法,它创建独立连接,不参与轮询,也不受rw_separate控制
真正容易被忽略的点在于:配置结构比语法更重要,read 少一层方括号、deploy 写成字符串、charset 不统一,都会导致“看起来配对了,实则全走主库”。验证是否生效,最直接的方式是开 MySQL general_log,看实际连接的是哪个 IP。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











