TP6必须配置deploy=>1和rw_separate=>true才能启用读写分离,read必须为二维数组且含完整连接参数,事务、锁查询或master()调用会强制走主库。

TP6 必须用 deploy + rw_separate,不能沿用 TP5 的 read_master
ThinkPHP 6.x 完全不识别 read_master 配置项,哪怕你照着 TP5 文档写 'read_master' => true,它也只会静默忽略。Aurora 场景下必须启用 deploy => 1 和 rw_separate => true,否则所有查询默认走 default 所指的主连接(也就是你配的 Aurora Writer Endpoint),从库永远不生效。
常见错误是把 Aurora 的 Reader Endpoint 直接塞进 DB_HOST 字符串里,比如 'DB_HOST' => 'mycluster.cluster-c9x8z2q1k2a4.us-east-1.rds.amazonaws.com,mycluster.cluster-ro-c9x8z2q1k2a4.us-east-1.rds.amazonaws.com'——TP6 不支持这种逗号分隔写法,会直接报错或 fallback 到单库模式。
-
deploy => 1是总开关,缺了它整个读写分离模块根本不会初始化 -
rw_separate => true单独设无效,必须和deploy => 1同时存在 - Aurora 的 Writer/Reader Endpoint 必须拆成独立配置:一个
write数组(对应 Writer),一个read二维数组(对应一个或多个 Reader)
read 必须是二维数组,哪怕只配一个 Aurora Reader
TP6 对 read 的结构校验极严:写成一维数组(如 'read' => ['hostname' => '...'])会导致启动时报 Invalid write database config 或静默失效;必须包一层,写成 'read' => [['hostname' => 'mycluster.cluster-ro-xxx.us-east-1.rds.amazonaws.com']]。
Aurora 多 Reader 场景下,read 就是二维数组,每个元素是一套完整 MySQL 连接参数:
'read' => [
[
'type' => 'mysql',
'hostname' => 'mycluster.cluster-ro-c9x8z2q1k2a4.us-east-1.rds.amazonaws.com',
'database' => 'myapp',
'username' => 'ro_user',
'password' => 'xxx',
'charset' => 'utf8mb4',
'hostport' => 3306,
],
[
'type' => 'mysql',
'hostname' => 'mycluster.cluster-ro-c9x8z2q1k2a4.us-west-2.rds.amazonaws.com',
'database' => 'myapp',
'username' => 'ro_user',
'password' => 'xxx',
'charset' => 'utf8mb4',
'hostport' => 3306,
],
]
- 每个
read子数组必须含hostname、database、username、password、charset,少一个就抛Database config read_config is invalid - 字符集务必统一,Aurora 默认推荐
utf8mb4,若主库配了utf8mb4而某个 Reader 配成utf8,emoji 字段可能乱码或写入失败 - TP6 默认轮询(
round),不支持权重或故障转移——某个 Reader 不可用时,连接会直接超时报错,不会自动跳过
事务内、带锁查询、显式调用 master() 会强制走 Writer
Aurora 的 Reader 实例默认不支持事务内读写混合,TP6 为安全起见,只要检测到当前处于事务中(Db::startTrans() 或闭包事务),所有查询(包括 select())都会强制路由到 write 连接,即 Writer Endpoint。
以下情况也会绕过 read,直连 Writer:
- 调用了
->lock(true)或原生 SQL 含FOR UPDATE/LOCK IN SHARE MODE - 链式调用中写了
->master(true),后续所有操作锁定到主库 - 用了
Db::connect('xxx')—— 它创建全新连接实例,完全不参与read/write路由逻辑 - 模型里手动调了
$this->db()->master(),等同于全局切主
所以别指望 Db::table('user')->select() 在事务里还能打到 Reader;真有强一致性读需求,得靠 Aurora 的 aurora_replica_read_consistency 参数或手动指定 useReadConnection() 并接受短暂延迟。
Aurora 延迟敏感场景要加 slave_no_delay
Aurora Reader 存在毫秒级复制延迟(通常 read 配置里显式加 'slave_no_delay' => true:
'read' => [[
'hostname' => 'mycluster.cluster-ro-xxx.us-east-1.rds.amazonaws.com',
'slave_no_delay'=> true,
// 其他字段...
]]
这个参数会让 PDO 连接时设置 PDO::MYSQL_ATTR_READ_DEFAULT_FILE,促使 MySQL 客户端优先选择延迟更低的副本(Aurora 内部机制)。但它不是万能的——无法消除延迟,只是降低概率;真正需要强一致性的读,仍应走 Writer 或用 Aurora 的 SELECT ... FOR UPDATE 显式加锁。
最易被忽略的是:TP6 不自动识别 SQL 类型,value()、column() 等纯读方法虽可能走 Reader,但一旦前面执行过 INSERT,TP6 内部标记未清,后续 select() 可能误判为“需同步读”,直接回 Writer——这在高并发写后紧接读的场景下特别隐蔽。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











