thinkphp 6 多数据库需在 config/database.php 的 'connections' 中定义唯一连接名(如 'slave_db'),通过 db::connect('slave_db') 显式调用,模型用 protected $connection = 'slave_db' 指定,跨库 join 应改用原生查询或分查合并。

ThinkPHP 6 多数据库配置怎么写
ThinkPHP 6 不支持在 database.php 里直接写多个同类型连接数组,必须用「连接池」方式注册额外连接。默认的 mysql 连接走 default 配置,其他库得显式定义名称并绑定完整参数。
正确做法是在 config/database.php 的 'connections' 下新增键值对,例如:
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'db_main',
// ... 其他参数
],
'slave_db' => [
'type' => 'mysql',
'hostname' => '192.168.1.100',
'database' => 'db_slave',
'username' => 'read_only',
'password' => 'xxx',
'charset' => 'utf8mb4',
'prefix' => '',
],
],
- 每个连接名(如
slave_db)必须全局唯一,且不能和内置驱动名冲突(比如别叫mysql或pgsql) -
prefix建议设为空字符串,避免跨库时表名被自动拼接前缀导致查不到 - 如果主从分离,不要指望 TP 自动路由;
slave_db只是“可选连接”,不调用就不会用
Db::connect() 调用多库的实际写法
想查 slave_db 里的数据,不能写 Db::name('user')->select() —— 它永远走默认连接。必须用 Db::connect('slave_db') 显式切换,且后续所有链式操作都绑定该连接。
常见错误写法:Db::connect('slave_db')->name('user')->where(...)->select() 看似没问题,但一旦中间加了 ->cache() 或 ->useSoftDelete(),就可能因底层连接复用逻辑出错。
- 推荐封装成独立查询对象:用
$db = Db::connect('slave_db');再调用$db->table('user')->select() - 不要混用
name()和table():前者依赖prefix,后者直传真实表名,跨库时更可控 - 事务只支持单连接内生效,
Db::connect('a')->startTrans()和Db::connect('b')->startTrans()是两个孤立事务
模型类如何指定非默认数据库连接
模型默认继承 think\Model,它只认 default 连接。要让某个模型(比如 UserLog)固定连 slave_db,得重写 getConnection() 方法或在初始化时绑定。
最稳的方式是在模型类里写:
protected $connection = 'slave_db';
这个属性会覆盖全局默认连接,且优先级高于配置文件中的 default。注意不是 $connectionName,也不是 $db —— 拼错就无效。
- 如果模型要动态切库(比如按用户 ID 散列到不同库),不能靠属性,得重写
getConnection()方法返回Db::connect($name) - 关联查询(
hasOne/belongsTo)不会自动跨库,关联模型仍走各自定义的$connection,需确保两边库能网络互通 - 软删除字段(
delete_time)的类型必须和目标库实际字段一致,否则useSoftDelete()会报 SQL 错误
跨库 JOIN 查询为什么总报错
MySQL 层面允许 SELECT * FROM db1.user u JOIN db2.order o ON u.id = o.user_id,但 ThinkPHP 的 QueryBuilder 默认把表名当成本地库前缀处理,生成的 SQL 会被加上当前连接的 prefix,导致变成 `db_main`.`db1.user` 这种非法结构。
根本原因:TP 的 table() 不支持带库名的字符串(如 'db1.user'),它会把点号当成别名分隔符。
- 绕过方法:用原生查询
Db::connect('master_db')->query("SELECT * FROM db1.user u JOIN db2.order o...") - 或者用
view()创建视图映射跨库表(需 DBA 权限),再当普通表查 - ORM 关联 + 跨库场景,建议拆成两次查询 + PHP 合并,比硬写 JOIN 更可控、更易调试
跨库本质是打破单库抽象,TP 的设计没把它当一等公民,硬凑语法糖反而容易掉坑里。真要高频跨库,不如直接上 Doctrine DBAL 或手写 PDO。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











