ThinkPHP多库连接必须在config/database.php的connections数组中预定义键名,Db::connect()仅支持该数组中的键名;临时传数组、含点号或大写字母的连接名会报错;读写分离需手动分库查询合并;跨库同步须按主键分片insertAll;.env无法定义多库结构,仅能覆盖扁平变量。
ThinkPHP 连接多个数据库,核心不是“能不能”,而是“怎么配才不翻车”——
传的必须是
里预定义的连接键名,临时传数组或拼 host 是高危操作,容易连错库、耗尽连接数、中文乱码。
database.
php
里必须用 connections 定义完整连接,不能靠 Db::connect([]) 动态凑
ThinkPHP 6+ 的多库支持只认
中
数组下的键名。你写
,框架就去这个数组里找
对应的完整配置。
常见错误:
复制粘贴后只改了
,忘了改
或
,结果两个连接都指向同一台 MySQL 实例
漏写
,框架用默认 mysql 驱动去解析 PostgreSQL 配置,报错
连接名含点号(如
)或大写字母,
直接抛出
在循环里反复调用
,每次新建连接不复用,高并发下 MySQL 报
正确写法示例:
立即学习
“
PHP免费学习笔记(深入)
”;
读写分离不是自动的,模型 $connection 和 Db::connect() 行为完全不同
模型类里设
,只影响该模型的主表操作;但
关联查询时,关联模型仍走自己的
,不会跨库 join —— MySQL 本身就不支持跨实例 join,TP 也不会帮你合并数据。
所以别指望一个
能自动从两个库捞数据。真要关联,得手动查两次再 PHP 合并:
先用
再用
最后用 PHP 按
键对齐
另外:
是模型初始化时读取一次的静态绑定,运行中 reload config 不会刷新它;想动态切库,老老实实用
显式调用。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
跨库同步必须分片 + insertAll,禁用 limit/offset 分页
全量导数据不是
然后
—— 内存爆、事务长、锁表久,还可能因中间删改导致漏同步或重复写入。
可靠做法是按主键范围分片:
先查源表
和
用
每块用
查,避免 offset 跳行
目标库写入必须用
,不是
—— 前者单条 SQL,后者 N 条 SQL,性能差一个数量级
如果两个库字符集不同(比如源库
,目标库
),必须在各自连接配置里显式写
,否则中文插入会截断或乱码
示例关键片段:
.env 文件只能覆盖扁平变量,不能定义多库结构
文件只支持键值对,比如
,它会被映射成
注入到
的默认连接里。但它**无法定义第二个连接**,比如你没法在 .env 里写
然后让框架自动识别为
。
所以多库配置必须硬编码在
的
数组里。
只能用于切换环境参数(如 dev/staging 的 host/port),不能替代结构化配置。
顺带一提:改完
或
后,别忘了清缓存:
,否则旧配置还在生效。
Db::connect('xxx')database.phpconfig/database.php'connections'Db::connect('log_db')'log_db'databasehostnameport'type' => 'mysql'Class 'PDO' not found'log.db'Db::connect()Connection not found: log.dbDb::connect(['hostname' => ...])Too many connectionsreturn [
'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',
],
],
];protected $connection = 'mysql_read';with()$connectionUser::with('profile')->select()Db::connect('mysql')->table('user')->select()Db::connect('log_db')->table('user_log')->where('user_id', 'in', $userIds)->select()user_id$connectionDb::connect('xxx')select * from Aforeach + insertmin(id)max(id)for ($i = $min; $i 切块where('id', 'between', [$start, $end])insertAll($rows)foreach + insert()utf8mb4gbk'charset' => 'xxx'$step = 5000;
for ($start = $minId; $start <= $maxId; $start += $step) {
$end = min($start + $step - 1, $maxId);
$rows = Db::connect('mysql')->table('order')->where('id', 'between', [$start, $end])->select();
if (!empty($rows)) {
Db::connect('backup_db')->table('order')->insertAll($rows);
}
}.envDB_HOST=127.0.0.1db.hostdatabase.phpLOG_DB_HOST=192.168.1.11connections.log_db.hostnamedatabase.phpconnections.envdatabase.php.envphp think clear:config