跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

ThinkPHP怎么连接多个数据库_ThinkPHP多数据库读写分离配置方案【技巧】

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
正确写法示例: 立即学习 “ PHP免费学习笔记(深入) ”;
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')
显式调用。 PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 跨库同步必须分片 + 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 <= $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); } }
.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
,否则旧配置还在生效。

相关文章