必须按ThinkPHP版本选择对应配置:TP5用deploy+rw_separate+slave一维数组;TP6用read二维数组+write单数组且default为mysql;TP8需.env设DB_DEPLOY=1和DB_RW_SEPARATE=true,并用filter_var转布尔值。

要在ThinkPHP项目中让SELECT查询自动走从库、INSERT/UPDATE/DELETE强制走主库,必须同时满足框架版本对应的配置结构、开关启用状态与连接参数格式——缺一不可,否则所有SQL都会沉默地落在主库上。
确认当前ThinkPHP版本并选择对应配置路径
打开项目根目录下的composer.json,查看"topthink/framework"行末尾的版本号:5.x、6.x、8.x写法完全不同,混用会导致读写分离完全失效。
ThinkPHP 5.0–5.1:必须用'deploy'=>1 + 'rw_separate'=>true + 'slave'一维数组;
ThinkPHP 6:废弃deploy/rw_separate,改用'read'(二维数组)+ 'write'(单数组),且default连接名必须为mysql;
立即学习“PHP免费学习笔记(深入)”;
ThinkPHP 8:需在.env中声明DB_DEPLOY=1和DB_RW_SEPARATE=true,再在database.php中用filter_var()转布尔值注入配置。
ThinkPHP 6 配置 read/write 结构(推荐用于新项目)
第一步:打开config/database.php,定位到'connections' => ['mysql' => [...]]部分;
第二步:删除所有旧字段如'deploy'、'rw_separate'、'slave',它们在TP6中已废弃;
第三步:在'mysql'数组内添加'write'子数组,填入完整主库参数(hostname、database、username、password缺一不可);
第四步:添加'read'子数组,注意【必须是二维数组,哪怕只配一个从库也要写成[0 => ['hostname' => '...']]】;
第五步:确保所有read节点与write节点的database值完全一致,否则跨库JOIN会报错。
ThinkPHP 5 配置 deploy + slave(兼容老项目)
方法一:字符串逗号分隔(适合各库参数高度一致)
在config.php中设置'DB_HOST' => '192.168.1.10,192.168.1.11,192.168.1.12',第一个地址自动视为主库,后续为从库轮询;
【DB_USER和DB_PWD若不同,必须严格按顺序用逗号分隔,错一位就会连错库】;
方法二:显式'slave'数组(推荐,更可控)
写成'slave' => [['host'=>'s1','username'=>'ro1','password'=>'p1'],['host'=>'s2']];
注意:【slave必须是一维扁平化数组,嵌套两层(如['s1'=>['host'=>'...']])会导致静默失败】;
无论哪种方式,都必须同时存在'deploy'=>1和'rw_separate'=>true,缺一不可。
ThinkPHP 8 启用环境变量驱动的读写分离
第一步:在项目根目录.env文件中追加两行:
DB_DEPLOY=1
DB_RW_SEPARATE=true
第二步:打开config/database.php,在'mysql'连接配置内部插入:
'deploy' => (int)Env::get('DB_DEPLOY', 0)
'rw_separate' => filter_var(Env::get('DB_RW_SEPARATE', 'false'), FILTER_VALIDATE_BOOLEAN)
这一步不能省略filter_var——传入字符串'true'不转布尔,TP8会当false处理,整个机制失效;
第三步:配置'read'为二维数组或通过Env::get('DB_SLAVE_HOSTS')动态解析,例如:
$slaves = array_map('trim', explode(',', Env::get('DB_SLAVE_HOSTS', '')));
'read' => array_map(fn($h) => ['host'=>$h,'port'=>3306], $slaves)



















