thinkphp 6 读写分离需同时启用 deploy => 1 和 rw_separate => true,缺一不可;read 必须为二维数组、write 为单维关联数组;事务、锁查询或 master() 调用强制走主库;db::connect() 独立于读写分离机制。

ThinkPHP 6 的 rw_separate 和 deploy 必须同时启用
读写分离在 TP6 中不是默认开启的“智能路由”,而是由两个硬性开关共同控制:deploy => 1 是总闸门,rw_separate => true 是具体策略开关。漏掉任一,read 和 write 配置都会被完全忽略——查询构造器会直接 fallback 到主库连接。
常见错误现象:配置了 read 数组但所有 select() 仍走主库;Db::table('user')->find() 没触发从库轮询。
-
deploy => 1必须写在具体连接配置里(比如'mysql'下),不能只写在顶层或default键下 -
rw_separate只在deploy === 1时生效,设成false或不写等价于关闭分离 - 主库配置中不能出现
read或write键以外的部署相关字段(如master_num、slave_no),TP6 会静默跳过或报错
read 必须是二维数组,write 必须是单维数组
TP6 对配置结构极其敏感:read 是从库列表,哪怕只有一个从库也必须写成数组套数组;write 是主库定义,只允许一个,且必须是关联数组(不能是数组套数组)。
典型错误配置:'read' => ['192.168.1.11'](一维,静默失效)、'write' => [['hostname' => '192.168.1.10']](二维,启动报错 Invalid write database config)。
- 正确
read示例:'read' => [['hostname' => '192.168.1.11'], ['hostname' => '192.168.1.12']] - 正确
write示例:'write' => ['hostname' => '192.168.1.10', 'username' => 'root'] -
read里每个子数组都是一套完整 MySQL 连接参数,host、port、username、password、database缺一不可,少一个就抛InvalidArgumentException: Database config read_config is invalid
事务内、带锁查询、手动调用 ->master() 会强制走主库
TP6 不解析 SQL 语义,而是靠操作类型和上下文做路由决策。一旦进入事务、显式加锁、或调用了 ->master(true),整个查询链路都会降级到主库,这是为数据一致性做的硬性保障,不是 bug。
容易被忽略的现象:Db::transaction(function () { Db::table('user')->where('id', 1)->find(); }); 看似只是读,但实际走主库;Db::table('user')->lock(true)->select() 也会绕过 read 配置。
- 事务中所有查询(包括
count()、value())全部走write连接 -
FOR UPDATE、LOCK IN SHARE MODE等原生 SQL 锁定语法,即使没用模型方法,也会被框架识别并路由到主库 -
->useReadConnection()在事务中无效,调用后仍走主库 - 全局
Db::master()或模型内$this->db()->master()会锁定后续所有查询到主库,需手动Db::slave()恢复(但事务中恢复也无效)
Db::connect('xxx') 和读写分离是两套独立机制
Db::connect('xxx') 是手动指定连接名,它绕过所有读写分离逻辑,直接使用 config/database.php 中 connections['xxx'] 的完整配置。它和 rw_separate 互不感知,也不能用来“临时切从库”实现负载均衡。
典型误用:Db::connect('mysql_slave')->table('user')->select() —— 这个查询永远只走 mysql_slave 那个固定连接,不会轮询、不会故障转移、也不会受 read 列表控制。
- 连接名(如
'mysql_slave')必须是合法 PHP 变量名:不能含点号('log.db')、不能大写('LogDB'),否则抛Connection not found -
Db::connect()创建的是全新连接实例,不复用、不共享上下文,高并发下易触发Too many connections - 若想让模型操作走特定从库,应通过
read_config配置 +->useReadConnection()触发内置轮询,而不是新建连接
schema_cache_type = redis 场景),否则旧连接信息会持续干扰新配置。主从延迟问题无法由框架解决,业务层需自行兜底——比如刚写完立刻要读,就得主动加 ->master(true)。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











