ThinkPHP6读写分离需同时满足'deploy'=>1、'rw_separate'=>true、'read'为非空数组三条件;Db::connect()指定独立连接不参与分离路由,Db::name()则依赖default配置;强制主库读须用Db::master()->table()->find()链式调用或置于事务中。
ThinkPHP 的读写分离不是“配了就能用”,而是依赖明确的配置开关和调用方式。主库强制读也不是加个方法就生效,关键在作用范围和链式调用是否延续。
读写分离必须显式启用
仅在 database.
php
里写上多个数据库地址或 'read' 数组,不会自动触发分离。TP6 要求同时满足三个条件:
'deploy' => 1
:开启多服务器部署模式,这是总闸门
'rw_separate' => true
:启用读写自动分离逻辑
'read' 配置非空且为数组
:例如
,不能是
、
或对象
缺一不可。漏掉
,整个读写分离模块根本不会初始化。
Db::connect() 与默认连接的区别
是显式指定一个已命名的连接配置(需在 database.php 的 connections 下定义),它独立于全局默认行为,不参与读写分离路由判断。
立即学习
“
PHP免费学习笔记(深入)
”;
或
则始终走
所指向的连接配置,是否走从库,完全取决于该配置中
是否开启、
是否有效。
常见误区:以为
后再调用
就能复用该连接——其实不行,
会重新绑定默认连接,必须写成
。
强制主库读的两种可靠方式
不是所有“想读主库”的场景都适合同一种写法,得看上下文:
单次查询强一致
:用
,
必须在链式开头,且后续所有操作(
、
)都在同一实例上调用
事务内读写混合
:无需额外指定,事务中所有操作(包括 SELECT)默认走主库,
已足够
错误写法:
—— 第一个
返回新实例但没被使用,第二个
仍是默认连接。
调试读写分离是否真生效
显示的只是 SQL 字符串,不体现执行位置。靠它判断走主还是从,100%误判。
真正有效的验证方式只有两个:
在从库执行
,过滤应用服务器 IP,确认是否有来自 PHP 的 SELECT 连接
在
的
方法中加日志,打印
和
标志
如果从库进程列表里始终看不到 SELECT,优先检查
是否为空、
是否遗漏、以及是否意外进入了事务或用了锁语句(如
)。
'read' => [['host' => '192.168.1.10']][]null'deploy' => 1Db::connect('mysql')Db::name('user')Db::table('user')default'rw_separate''read'Db::connect('slave_read')->table('user')->select()->table()Db::connect('slave_read')->table('user')->select()Db::master()->table('user')->where('id', 1)->find()master()wherefindDb::transaction(function () { Db::table('user')->find(); })Db::master(); Db::table('user')->find()master()Db::table()getLastSql()SHOW PROCESSLISTthink/db/Connection.phpconnect()$config['hostname']$isRead'read''deploy'lock(true)