ThinkPHP 8读写分离不生效的根本原因是rw_separate=>true未启用且deploy与rw_separate未正确置于connections['mysql']内部;二者必须同时开启并位于MySQL连接配置内,缺一不可。

ThinkPHP 8 数据库配置 deploy => 1 后读写分离不生效,**根本原因不是 deploy 开关没开,而是另外两个关键条件缺失或错位**:一是 rw_separate => true 没启用,二是这两个开关没放在 connections['mysql'] 的具体连接配置内部。
deploy=1 只是“入场券”,不是“自动执行器”
TP8 不会因为写了 deploy => 1 就自动分流读请求。它只是启动分布式模式的总开关,后续所有读写路由逻辑(比如 select 走从库、insert 走主库)都依赖 rw_separate => true 这个路由开关是否同时开启。两者必须共存且位置正确,缺一不可。
- 只开
deploy => 1,rw_separate是 false 或未定义 → 所有操作默认走主库 - 只开
rw_separate => true,但deploy是 0 或缺失 → 整个读写分离模块压根不初始化 - 两个都开了,但写在
default或connections外层 → 框架完全忽略,等同于没配
配置必须严格落在 mysql 连接内部
TP8 的读写分离是按连接粒度控制的,不是全局行为。你必须把 deploy 和 rw_separate 明确写进 connections['mysql'] 的数组里,而不是 config/database.php 的顶层或其他地方。
- ✅ 正确位置:
'connections' => ['mysql' => ['deploy' => 1, 'rw_separate' => true, 'read' => [...], 'write' => [...]]] - ❌ 错误位置:
'default' => [...]里写 deploy,或'connections' => ['deploy' => 1, 'mysql' => [...]] - 错误位置会导致 Db::name('user')->select() 看似正常执行,实则默默走主库,且无任何提示
read 配置结构错误也会让分离“静默失败”
即使两个开关都对,如果 read 不是二维数组(即数组套数组),TP8 在解析时会直接跳过从库配置,导致所有读操作 fallback 到主库,还可能报 Call to a member function query() on null。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 正确:
'read' => [['hostname' => '192.168.1.11', 'database' => 'myapp']] - ❌ 错误:
'read' => ['hostname' => '192.168.1.11'](一维数组,解析失败) - ⚠️ 注意:write 必须是单数组,不能写成二维;所有节点的
database名必须一致
环境变量没做布尔转换,导致 rw_separate 实际为 false
如果用 .env 控制开关(如 DB_RW_SEPARATE=true),TP8 内部用 === true 判断,而 Env::get() 返回的是字符串 'true',结果恒为 false。
- ✅ 正确写法:
'rw_separate' => filter_var(Env::get('DB_RW_SEPARATE', 'false'), FILTER_VALIDATE_BOOLEAN) - ❌ 错误写法:
'rw_separate' => Env::get('DB_RW_SEPARATE') - 同理,
deploy也需转整型:'deploy' => (int)Env::get('DB_DEPLOY', 0)



















