ThinkPHP6连接数过多主因是连接未释放、事务卡死或误启持久化;应查SHOW PROCESSLIST定位Sleep/Query/Locked状态连接,启用deploy=>1复用连接,严格管理事务并显式关闭CLI连接。

ThinkPHP6 连接数过多,90% 的情况不是数据库扛不住,而是连接没归还、事务卡死、或配置误启了无效的“持久化”——别急着调 max_connections,先看连接到底卡在哪。
查真实连接状态:SHOW PROCESSLIST 必须配合 Time 和 Command
光看连接总数没用。执行 SHOW PROCESSLIST 后重点关注:
- 状态为
Sleep且Time > 30的连接:大概率是 ThinkPHP 请求结束但连接没释放,常见于 CLI 任务未调Db::close()或异常中断 - 状态为
Query且Time > 60的连接:正在执行慢 SQL,得结合慢日志查具体语句(开slow_query_log,设long_query_time = 1) - 状态为
Locked或Waiting for table metadata lock:DDL 操作(如ALTER TABLE)阻塞了读写,不是连接池问题,是运维操作时机不对
deploy => 1 是 TP6 唯一靠谱的“长连接替代方案”,但配错等于白配
TP6 不支持 PDO 原生持久连接(PDO::ATTR_PERSISTENT 在连接池销毁逻辑里被绕过),真正起效的是开启部署模式复用连接对象:
- 必须在
config/database.php的对应数据库配置块里加'deploy' => 1,不是全局开关 - 只对同主机、同库名、同账号的请求生效;换一个
database名就会新建连接池 -
'pool_size' => 20可控空闲连接上限,但注意它不清理超时连接——idle_timeout在 TP6.1 中实际未生效 - 如果用了
'break_reconnect' => true,失败连接直接丢弃不归还,会加速耗尽;高并发下建议关掉
事务没提交是最隐蔽的连接卡死原因
一旦调用 $db->startTrans(),该连接就从池中被独占,直到 commit() 或 rollback()。漏写或异常未捕获,连接就永远挂在那里:
立即学习“PHP免费学习笔记(深入)”;
- 所有事务块必须用
try...catch包裹,catch里强制$db->rollback() - 避免在事务里做 HTTP 请求、
sleep()、文件读写等耗时操作 - 开发期打开
'debug' => true,盯日志里有没有长时间未结束的START TRANSACTION - CLI 长任务(如队列消费)务必在循环末尾显式调
Db::close(),否则连接不会自动释放
多库连接场景下,Db::connect('xxx') 调用不当会指数级放大连接数
每个 Db::connect('log_db') 都会创建独立连接池,不是复用默认池。错误用法会让连接数翻倍甚至失控:
- 禁止在循环里反复调
Db::connect(['hostname' => 'x']),每次都是新连接 - 连接名只能是
config/database.php中'connections'数组里预定义的键(如'log_db'),不能含点号、大写字母或临时数组 - 模型类指定
protected $connection = 'log_db'是安全的,但with()关联查询仍走各自模型的连接,不会跨库合并——别指望一条语句连两个库 - 临时切换连接后,别混用
name()(依赖 prefix)和table()(直传表名),跨库时table()更可控
最易被忽略的一点:TP6 的连接池不自动 kill 空闲连接,wait_timeout 是 MySQL 服务端参数,和 PHP 层是否复用无关。连接数压不下来,往往是因为你既没让应用及时归还,也没让 MySQL 主动清理。



















