thinkphp 8 的数据库读写分离需同时配置 deploy => 1(整数)和 rw_separate => true,且必须置于具体连接(如 mysql)中;deploy => 1 要求 hostname 为含 write/read 键的关联数组,端口须显式声明,事务内所有操作强制走写节点。

ThinkPHP 8 的数据库部署模式不是靠开关“开/关”决定的,而是由 deploy 和 rw_separate 两个配置项共同生效——缺一不可,且必须配在具体连接里(比如 mysql),不能只写全局。
deploy=1 是分布式模式的硬性前提
不设 deploy=>1,哪怕写了 rw_separate=>true,TP8 也完全忽略读写分离逻辑,所有查询都走默认主机列表第一台。这个值必须是整数 1,写成字符串 "1" 或布尔 true 都无效。
-
deploy=>0:集中式,hostname只能是字符串(如"127.0.0.1"),写数组会报错 -
deploy=>1:分布式,hostname必须是关联数组,含write和read键,值为字符串数组 - 主从节点地址必须可直连,TP8 不做 DNS 轮询或健康检查,挂掉的节点会导致连接失败
rw_separate=true 才真正启用读写分离路由
仅设 deploy=>1 不代表自动读写分离;必须同时设 rw_separate=>true,框架才会在执行 SELECT 时挑 read 列表,执行 INSERT/UPDATE/DELETE 时固定走 write 列表第一项。
- 写操作永远只用
write[0],不支持多主写入(如双主同步场景需自行封装) - 读操作默认随机选一个
read节点,不支持权重、延迟感知或一致性读(比如刚写完立刻查可能读不到) - 事务内所有语句强制走写节点,哪怕全是
SELECT——这是安全设计,不是 bug
hostname 必须按 write/read 结构组织,不能扁平化
常见错误是把主从地址写成 hostname => ["master", "slave1", "slave2"],这在 deploy=>1 下直接报 Invalid hostname format。
- 正确结构:
'hostname'=>['write'=>['master1:3306','master2:3306'],'read'=>['slave1:3306','slave2:3306']] - 如果只有单主+多从,
write数组仍要保留,哪怕只有一个元素 - 端口必须显式写出(如
"192.168.1.10:3307"),不能依赖hostport配置覆盖
从库节点没做 GTID 或半同步,容易查到脏数据
TP8 的读写分离是纯 SQL 类型判断,不感知 MySQL 复制状态。如果从库延迟高、中断过或启用了 read_only=OFF,应用层无法察觉。
- 上线前务必确认所有
read节点的Seconds_Behind_Master稳定为 0 - 避免在
SELECT后紧跟强一致性要求的业务逻辑(例如查余额后立即扣减) - 若需强制走主库读,可用
Db::connect('mysql')->master()->table(...)->select()
最易被忽略的是 deploy 和 rw_separate 必须同时存在且类型严格匹配,少一个或类型错,整个集群配置就退化成单点——看着配了,实际没生效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











