TP5 必须通过置空 PDO 实例并清空连接池缓存来真正释放数据库连接,仅调用 protected close() 或清空 linkID 无效,否则 MySQL 连接持续占用。

ThinkPHP5 没有暴露 close() 方法,也不能直接调用 __destruct(),强行模拟析构行为(如 Db::getConnect()->__destruct())在 TP5 中不可靠,且可能破坏连接池状态。必须通过底层 PDO 实例或连接管理器显式释放。
TP5 的 Connection 类不提供 public close() 方法
TP5.1 的 think\db\Connection 类中,close() 是 protected 方法,未被公开,也未被 Db 门面代理。即使反射调用,也会跳过连接池回收逻辑,导致后续请求仍复用已“逻辑关闭”但未真正释放的句柄。
-
Db::getConnect()返回的是连接实例,但调用其close()会报 Fatal error:Call to protected method - 手动置空
$this->link或$this->links属于侵入式操作,升级后极易失效 - TP5 默认启用连接池(
deploy配置为 0 时),连接不会随脚本结束立即释放,而是归还池中等待复用
正确做法:用 PDO 实例的 null 赋值 + 清空连接池缓存
TP5 底层使用 PDO,而 PDO 连接资源可通过将 PDO 对象设为 null 触发析构并断开物理连接。但需配合清理连接池中的缓存引用,否则下次 Db::table() 仍可能取出旧连接。
- 先获取当前连接的 PDO 实例:
$pdo = Db::getConnect()->getPdo(); - 再将其置空:
$pdo = null; - 最后清空连接池中该连接的缓存:
Db::getConnect()->links = [];(仅对当前连接生效) - 若使用多数据库配置(如
db2),需指定连接名:Db::connect('db2')->getPdo();
长周期脚本(如 queue:work)必须主动清理
在 while(true) 循环中反复调用 Db::table(),每次都会从连接池取连接,但 TP5 不自动回收“闲置连接”,累积会导致 MySQL Too many connections。
立即学习“PHP免费学习笔记(深入)”;
- 不要依赖脚本结束自动释放——CLI 模式下进程常驻,连接一直挂着
- 每个任务处理完后,应执行清理(上面两步),而非只在 finally 块里做
- 避免在事务中提前 close,否则
commit()或rollback()会失败并抛出 PDOException - 若用
Db::transaction()包裹,清理动作必须放在事务块 之后,且确认已提交/回滚
PDOConnection 的 linkID 置 null 并不等于断开连接
TP5.1 中 PDOConnection 的 close() 方法只是把 $this->linkID 设为 null,并未调用 $pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS) 或发送 KILL 命令;它只是让下次 initConnect() 强制重连,但旧连接仍在 MySQL 端存活。
- MySQL 的
wait_timeout默认 28800 秒(8 小时),不主动 kill,连接就一直占着 - 真正释放需靠 PDO 对象销毁(即
$pdo = null)触发其内部析构 - 所以仅清空
linkID或links数组,只是“骗过 TP5”,对 MySQL 无效



















