thinkphp 6.0 多数据库本质是按需创建独立 query 实例,db::connect() 必须传配置键名(如'mysql2'),不支持 dsn 字符串或数据库名;传错抛 connection not found 异常;$connection 属性仅初始化时生效,跨库关联需手动分查,事务与连接严格绑定,无内置连接池。

ThinkPHP 6.0 的多数据库不是“切换默认连接”,而是按需创建独立连接实例——Db::connect() 返回的是全新 Query 对象,不改变任何全局状态。误以为调一次就能让后续所有查询自动走新库,是绝大多数人踩坑的起点。
Db::connect() 参数必须是配置键名,不是数据库名或 DSN
传错参数会直接抛出 Connection not found: xxx 异常,而不是静默降级。
-
Db::connect('mysql2')✅ —— 前提是config/database.php的connections数组里已定义键名为'mysql2'的完整配置 -
Db::connect('user_db')✅ —— 键名不能含点号、大写字母或空格,否则解析失败 -
Db::connect('user')❌ —— 如果配置里写的是'user_db',这里写'user'就找不到 -
Db::connect('mysql://...')❌ ——Db::connect()不接受 DSN 字符串;要用 DSN 必须传数组:Db::connect(['type'=>'mysql', 'dsn'=>'mysql:host=...']) -
Db::connect(['hostname'=>'127.0.0.1', 'database'=>'test'])✅ —— 临时数组配置可行,但不进连接池,无法复用,慎用于高频场景
模型类里用 $connection 绑定库,只在初始化时生效
这个属性不是运行时响应式变量,改了配置或换租户 ID 后不会自动刷新。
-
protected $connection = 'mysql_read';✅ —— 仅对当前模型的find()、save()、delete()等操作生效 - 关联查询(如
with('profile'))默认仍走被关联模型自己的$connection,不会继承主模型的连接 - 若
User模型绑了'mysql_read',而Profile模型没设$connection,那Profile仍走default库 - 跨库关联无法用
join()实现 —— MySQL 层面不支持跨库 JOIN(除非用db_name.table_name写死,但 TP 不自动拼接)
多租户动态注册连接必须用 Db::setConnectConfig()
靠中间件解析租户标识后实时生成配置,再注册到连接池,否则 Db::connect('tenant_123') 一定报错。
- 在全局中间件中做:
Db::setConnectConfig('tenant_'.$tenantId, $config);,之后才能Db::connect('tenant_'.$tenantId) - 不要在控制器里反复调用
Db::setConnectConfig()—— 它不校验重复注册,可能覆盖已有连接 - 租户量大时,建议加一层缓存(如
app()->cache->get('db_config_'.$tenantId)),避免每次请求都查库或计算配置 -
Db::setConnectConfig()是 ThinkPHP 6.1+ 才稳定支持的方法;6.0 基础版需手动补丁或升级
事务和连接复用是两个极易忽略的硬限制
同一个 Db::connect() 实例内事务正常,但不同实例之间完全隔离 —— 这不是 Bug,是 PDO 本身机制决定的。
-
$db1 = Db::connect('a'); $db1->startTrans(); $db1->insert(...); $db1->commit();✅ -
$db1->startTrans(); $db2->insert(...); $db1->commit();❌ ——$db2的操作不在事务内,且无法回滚 - 高频场景下(如日志批量写入),务必复用
$logDb = Db::connect('log');,别在循环里反复调用Db::connect(),否则快速触发Too many connections - 连接复用不等于连接池 —— ThinkPHP 6.0 没有内置连接池管理,
Db::connect()每次都是新建 PDO 实例,复用靠你自己存变量或绑定容器
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











