ThinkPHP 5.1 分布式数据库本质是主从读写分离,依赖DB_HOST逗号分隔字符串识别主从(首IP为主库),需同时开启DB_DEPLOY_TYPE=1和DB_RW_SEPARATE=true,配置错误将静默退化为单机连接。

ThinkPHP 5.1 实现分布式数据库连接,本质不是“多库并行”,而是主从读写分离——写操作走主库,读操作按策略分发到从库。它不支持跨库 JOIN 或自动分片,配置错一个键名或类型,就会静默退化为单机文件式连接,连错误都不报。
DB_HOST 多地址写法必须用逗号分隔,且顺序不能颠倒
TP5.1 的分布式识别完全依赖 DB_HOST 字符串的逗号分割逻辑,而不是数组:
- ✅ 正确:
'DB_HOST' => '192.168.10.10,192.168.10.11,192.168.10.12'(第一个是主库,后面是只读从库) - ❌ 错误:
'DB_HOST' => ['192.168.10.10', '192.168.10.11'](TP5.1 会忽略整个配置,回退到默认 localhost) - ❌ 错误:
'DB_HOST' => '192.168.10.11,192.168.10.10'(主库不在首位,INSERT/UPDATE可能发到从库,导致报错ERROR 1290 (HY000): The MySQL server is running with the --read-only option)
其他字段如 DB_USER、DB_PWD、DB_NAME 同样支持逗号分隔,但若所有节点账号一致,可只写一个值(如 'DB_USER' => 'root'),框架会复用;若不同,则必须严格对齐顺序,否则连接凭据错配。
DB_DEPLOY_TYPE 和 DB_RW_SEPARATE 必须同时为 true
这两个开关是触发读写分离的硬性条件,缺一不可:
立即学习“PHP免费学习笔记(深入)”;
-
'DB_DEPLOY_TYPE' => 1:启用分布式部署模式(0 = 单机) -
'DB_RW_SEPARATE' => true:显式开启读写分离 - 漏掉任一,哪怕
DB_HOST写了十个 IP,所有查询(包括Db::table()->select())都只打向第一个地址
注意:DB_MASTER_NUM 默认为 1,表示前 N 个 DB_HOST 地址为主库。除非你有多个可写节点(如 MGR 多主),否则不要改动它——改了反而会导致写请求被轮询到从库。
从库同步延迟下,强一致性读要手动切主库
TP5.1 的读写分离是“语义级”的:所有 SELECT 自动走从库,但框架**不感知复制延迟**。如果刚插入一条记录就立刻查,大概率查不到:
- 临时方案:用
Db::master()->table()->where(...)->find()强制走主库 - 避免滥用:频繁调用
master()会绕过负载均衡,压垮主库 - 根本解法:业务层加缓存(如 Redis)或设置合理的
slave_net_timeout+MASTER_DELAY(MySQL 5.6+)
另外,Db::transaction() 内部所有操作(含 SELECT)默认走主库,这是安全设计,无需额外干预。
配置项位置必须在 database.php,不是 .env 或 config.php
TP5.1 的数据库驱动初始化只读取 config/database.php,其他位置的配置无效:
- ❌ 在
.env里写DB_HOST=...:完全不生效 - ❌ 在
config/config.php或模块级config.php中覆盖:会被 database.php 覆盖,或因加载顺序问题被忽略 - ✅ 正确路径:
app/config/database.php(或入口定义的配置目录),返回数组中直接写键值
最容易被忽略的是:一旦启用了分布式,DB_PORT 如果只写一个值(如 'DB_PORT' => '3306'),框架会把它广播给所有节点;但如果某个从库用了非标端口,就必须写成 'DB_PORT' => '3306,3307,3306',严格对齐顺序——这里没有容错,错一位就连接失败。



















