thinkphp多库连接必须在config/database.php的connections数组中预定义键名,db::connect()仅支持该数组中的键名;临时传数组、含点号或大写字母的连接名会报错;读写分离需手动分库查询合并;跨库同步须按主键分片insertall;.env无法定义多库结构,仅能覆盖扁平变量。

ThinkPHP 连接多个数据库,核心不是“能不能”,而是“怎么配才不翻车”——Db::connect('xxx') 传的必须是 database.php 里预定义的连接键名,临时传数组或拼 host 是高危操作,容易连错库、耗尽连接数、中文乱码。
database.php 里必须用 connections 定义完整连接,不能靠 Db::connect([]) 动态凑
ThinkPHP 6+ 的多库支持只认 config/database.php 中 'connections' 数组下的键名。你写 Db::connect('log_db'),框架就去这个数组里找 'log_db' 对应的完整配置。
常见错误:
- 复制粘贴后只改了
database,忘了改hostname或port,结果两个连接都指向同一台 MySQL 实例 - 漏写
'type' => 'mysql',框架用默认 mysql 驱动去解析 PostgreSQL 配置,报错Class 'PDO' not found - 连接名含点号(如
'log.db')或大写字母,Db::connect()直接抛出Connection not found: log.db - 在循环里反复调用
Db::connect(['hostname' => ...]),每次新建连接不复用,高并发下 MySQL 报Too many connections
正确写法示例:
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => '192.168.1.10',
'database' => 'main_db',
'username' => 'app_rw',
'password' => 'xxx',
'charset' => 'utf8mb4',
],
'log_db' => [
'type' => 'mysql',
'hostname' => '192.168.1.11',
'database' => 'log_db',
'username' => 'app_ro',
'password' => 'yyy',
'charset' => 'utf8mb4',
],
],
];
读写分离不是自动的,模型 $connection 和 Db::connect() 行为完全不同
模型类里设 protected $connection = 'mysql_read';,只影响该模型的主表操作;但 with() 关联查询时,关联模型仍走自己的 $connection,不会跨库 join —— MySQL 本身就不支持跨实例 join,TP 也不会帮你合并数据。
所以别指望一个 User::with('profile')->select() 能自动从两个库捞数据。真要关联,得手动查两次再 PHP 合并:
- 先用
Db::connect('mysql')->table('user')->select() - 再用
Db::connect('log_db')->table('user_log')->where('user_id', 'in', $userIds)->select() - 最后用 PHP 按
user_id键对齐
另外:$connection 是模型初始化时读取一次的静态绑定,运行中 reload config 不会刷新它;想动态切库,老老实实用 Db::connect('xxx') 显式调用。
跨库同步必须分片 + insertAll,禁用 limit/offset 分页
全量导数据不是 select * from A 然后 foreach + insert —— 内存爆、事务长、锁表久,还可能因中间删改导致漏同步或重复写入。
可靠做法是按主键范围分片:
- 先查源表
min(id)和max(id) - 用
for ($i = $min; $i 切块 - 每块用
where('id', 'between', [$start, $end])查,避免 offset 跳行 - 目标库写入必须用
insertAll($rows),不是foreach + insert()—— 前者单条 SQL,后者 N 条 SQL,性能差一个数量级 - 如果两个库字符集不同(比如源库
utf8mb4,目标库gbk),必须在各自连接配置里显式写'charset' => 'xxx',否则中文插入会截断或乱码
示例关键片段:
$step = 5000;
for ($start = $minId; $start table('order')->where('id', 'between', [$start, $end])->select();
if (!empty($rows)) {
Db::connect('backup_db')->table('order')->insertAll($rows);
}
}
.env 文件只能覆盖扁平变量,不能定义多库结构
.env 文件只支持键值对,比如 DB_HOST=127.0.0.1,它会被映射成 db.host 注入到 database.php 的默认连接里。但它**无法定义第二个连接**,比如你没法在 .env 里写 LOG_DB_HOST=192.168.1.11 然后让框架自动识别为 connections.log_db.hostname。
所以多库配置必须硬编码在 database.php 的 connections 数组里。.env 只能用于切换环境参数(如 dev/staging 的 host/port),不能替代结构化配置。
顺带一提:改完 database.php 或 .env 后,别忘了清缓存:php think clear:config,否则旧配置还在生效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











