Db::connect()报“Connection not found”根本原因是ThinkPHP连接池未自动注册新连接名,需显式配置或调用Db::setConfig()注入;多库切换须复用Query实例,事务不跨库。

为什么 Db::connect() 报 Connection not found
根本原因不是配置写错了,而是 ThinkPHP 的连接池机制在多数据库场景下默认不自动注册新连接名。你配了 database2,但没显式告诉框架“这个连接要加载”,它就真当不存在。
常见错误现象:Connection not found: database2;或者切换后仍查主库(database1)——其实是没切成功,降级用了默认连接。
- 确保
config/database.php里已定义完整连接数组,键名必须和Db::connect('xxx')中的字符串完全一致(区分大小写) - 不要依赖
db()辅助函数切换,它只认默认连接;必须用Db::connect('database2') - 如果连接配置在运行时动态生成(比如从数据库读取),需手动调用
Db::setConfig()注入,否则连接名不会进连接池
如何安全切换并复用连接实例
ThinkPHP 的 Db::connect() 默认每次调用都新建连接对象,频繁切换会导致连接数暴涨、事务失效。正确做法是复用单例,尤其在同一个请求周期内。
- 首次调用
Db::connect('database2')后,把返回的Query实例存到变量或容器中,后续操作都基于该实例 - 避免在循环里反复调用
Db::connect(),哪怕参数相同,也会创建新连接 - 跨模块使用时,推荐绑定到容器:
app()->bind('db2', function () { return Db::connect('database2'); });,再通过app('db2')获取
事务跨库失败的典型陷阱
ThinkPHP 原生不支持跨数据库事务。如果你在 database1 开启事务,又用 Db::connect('database2') 操作另一库,两个连接互不感知,commit() 只对当前连接生效。
立即学习“PHP免费学习笔记(深入)”;
- 不要指望
Db::startTrans()能管住多个Db::connect()实例 - 真要强一致性,得用分布式事务方案(如 Seata),或退而求其次:先写主库,再发消息通知副库异步写入
- 本地测试时容易忽略这点——单库事务能过,一上多库环境立刻数据不一致
配置文件里 default 和 connections 的实际影响
default 只决定 db() 和未指定连接的 Db::name() 用哪个;connections 下的每个键才是真实可用的连接名。很多人把连接配在 connections 里却忘了删掉旧的顶层配置,导致同名冲突或覆盖。
- ThinkPHP 6.1+ 强烈建议只用
connections数组方式定义,废弃顶层平铺配置 - 若使用
.env,确保DATABASE_CONNECTIONS_DATABASE2_HOST这类环境变量命名与配置结构匹配,否则会静默 fallback 到空值 - 配置热更新不生效?检查是否启用了
app_debug = false,此时配置被缓存,改完要清runtime/cache/
最易被忽略的是连接名作用域——它只在当前请求生命周期内有效,别试图在队列任务或 Swoole 长连接里复用主进程的 Db::connect() 实例。


















