db::connect() 创建独立连接实例,不切换默认连接;需显式使用返回对象或提前注册绑定才能生效,否则仍走默认库。

ThinkPHP 6 的 Db::connect() 不是“切换”连接,而是新建一个独立连接实例——调用它不会改变默认连接,也不会影响后续 Db::table() 或模型查询的行为。想让某次查询走指定库,必须显式使用该实例;想让整个请求走新库,得在任何数据库操作前注册并绑定标识。
Db::connect('mysql2') 为什么查的还是默认库?
因为 Db::connect('mysql2') 返回的是一个全新 Db 对象,和全局默认连接完全隔离。你没把它存下来、也没在查询中显式使用,那它就只是个被丢弃的对象。
- 错误写法:
Db::connect('mysql2'); Db::table('user')->select();→ 后者仍走默认库 - 正确写法:
$logDb = Db::connect('mysql2'); $logDb->table('log')->select(); - 配置名
'mysql2'必须提前在config/database.php的connections数组里定义好,不能只传 DSN 或数组 - 如果配置漏了
database字段,会报No database selected,不是连不上,是连上了但没选库
如何让模型类自动走指定库?
模型里的 $connection 属性是静态绑定的,只读取一次,对应配置文件中的键名(如 'mysql2'),不是运行时可变的变量。
- 固定库场景:直接在模型中声明
protected $connection = 'mysql2'; - 多租户动态场景:不能靠改
$connection,得在模型initialize()中手动注入连接对象,例如:$this->connection = app('request')->db; - 千万别在控制器里反复调用
Db::connect()然后赋值给模型的$connection—— 它不响应运行时变化
中间件里动态注册连接为何不生效?
因为 ThinkPHP 在第一次调用 Db::table() 或 Db::name() 时,就已经初始化并缓存了默认连接。中间件里再调 Db::connect(),只是新增一个连接实例,不会重置已建立的默认连接。
- 生效前提:必须在任何数据库操作之前完成连接注册与绑定
- 推荐做法:在中间件中解析租户标识(如子域名),组装配置数组,调用
Db::setConnectConfig('tenant_123', $config)注册,再通过app('request')->db = Db::connect('tenant_123');挂载到请求对象上 - 后续所有业务代码统一从
$request->db取连接,而不是用Db::table() - 高频切换时注意连接数:不要在循环里反复调
Db::connect(),复用同一个变量
事务跨库为什么一定失败?
ThinkPHP 的事务完全绑定在单个 PDO 实例上,不同 Db::connect() 返回的对象之间没有任何上下文共享机制。
-
$db1->startTrans()和$db2->startTrans()是两个孤立事务,无法合并提交或回滚 - 订单写主库、日志写日志库 → 不能靠框架事务保证一致性,得靠业务层补偿或最终一致性方案
- MySQL XA 事务 ThinkPHP 不支持,也不适合 Web 请求短生命周期场景
- 测试时看
show processlist,确认没有大量Sleep状态闲置连接堆积
真正麻烦的从来不是怎么切,而是切完之后要不要管连接生命周期、事务边界、以及模型是否还按你预期在跑——这些地方一疏忽,数据就容易错位或泄漏。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











