应开启 'break_reconnect' => true 实现自动重连,或禁用持久连接('params' => [pdo::attr_persistent => false]),避免复用已断开连接;tp 官方不支持连接池,需借助 swoole 协程池手动实现。

MySQL 连接超时后 TP 报 SQLSTATE[HY000] [2006] MySQL server has gone away 怎么办
这是最典型的连接空闲超时表现,不是 ThinkPHP 本身的问题,而是 MySQL 的 wait_timeout(默认 28800 秒,即 8 小时)和 interactive_timeout 生效后主动断开连接,而 TP 默认复用 PDO 连接句柄,没做失效检测。
解决思路不是单纯调大 MySQL 超时值,而是让 TP 在执行前确认连接是否还活着:
- 在数据库配置中开启
'break_reconnect' => true,TP 会在报错后自动重连一次(仅适用于单次查询失败场景) - 更稳妥的是配合
'deploy' => 0(单库模式)+'params' => [\PDO::ATTR_PERSISTENT => false],禁用 PDO 持久连接,避免连接被复用到已断开状态 - 若必须用长连接,需手动在每次查询前加
$this->query('SELECT 1')心跳探测——但不推荐,增加无谓开销
ThinkPHP 6/7 是否支持连接池?官方没提供,得自己搭
TP 原生不带连接池,think-swoole 扩展也只封装了协程 MySQL 客户端,并未实现连接复用调度逻辑。真要上连接池,得绕过 TP 的 Db 类,直接对接 Swoole\Coroutine\MySQL 或第三方协程池(如 swoole/co-pool)。
典型做法是:在 Swoole Server 启动时初始化一个协程池,把 Swoole\Coroutine\MySQL 实例存进去;业务中通过 $pool->get() 获取连接,用完 $pool->put($conn) 归还。注意两点:
- TP 的模型、查询构造器(
Db::table())完全无法接入这套机制,只能手写原生 SQL + 协程 MySQL 执行 - 连接池的
maxIdleTime必须小于 MySQL 的wait_timeout,否则池里躺着的“死连接”会直接导致查询失败
'persistent' => true 是长连接吗?别被名字骗了
TP 配置里的 'persistent' => true 只是透传给 PDO 的 PDO::ATTR_PERSISTENT,它依赖 PHP-FPM 的进程生命周期——每个 FPM worker 进程会缓存一个连接,进程结束才释放。这不是真正意义上的“长连接池”,也不跨进程共享。
实际效果受限明显:
- FPM 动态模式下,worker 频繁启停,持久连接基本无效
- 连接数 = 并发请求数 × worker 数,容易打爆 MySQL 的
max_connections - 一旦 MySQL 重启或网络闪断,这个“持久”连接就永远卡死,后续请求全挂
生产环境建议始终设为 false,靠数据库中间件(如 ProxySQL、MySQL Router)或应用层连接池来管理复用。
如何验证当前连接是否被复用?看 MySQL 的 Threads_connected
别只盯着 TP 日志,直接查数据库状态最准:
SHOW STATUS LIKE 'Threads_connected';
在高并发压测时反复执行这句,如果数值持续上涨且不回落,说明连接没被回收(可能是持久化开关开着,或没正确 close);如果数值稳定在 5–20 区间,说明连接复用正常。再结合慢日志里的 Connect 时间戳,能判断出连接是否真的“长”。
真正难处理的不是配置开关,而是混合使用 Db 类、原生 PDO、Swoole MySQL 时各自维护一套连接生命周期——这时候连接行为完全不可预测,最容易出现超时又不报错的静默失败。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











