break_reconnect仅在pdo异常且满足三条件时生效:驱动为pdo_mysql、非事务内、pdo::errmode设为exception;它捕获2006错误后重建连接并重试一次sql,但当前请求仍报错。

break_reconnect 必须设为 true,且仅对 PDO 异常生效;它不是“连接一断就自动恢复”,而是“查询失败后尝试重建连接并重试一次”,首次失败仍会报错。
为什么开了 break_reconnect 还是报 MySQL server has gone away
这不是配置没生效,而是你踩中了三个高频失效点:
-
type不是pdo_mysql:检查config/database.php中数据库类型,mysqli或mysql驱动不识别该参数 - 在事务中触发断连:
Db::startTrans()后连接失效,TP 直接抛异常,break_reconnect被跳过(避免事务语义污染) -
PDO::ATTR_ERRMODE没设为PDO::ERRMODE_EXCEPTION:若配置里params缺失此项,PDO 错误会被静默吞掉,框架根本收不到异常,自然不会触发重连
break_reconnect 生效时到底做了什么
它只在 query() 或 execute() 抛出 PDOException 后介入,流程是:
- 捕获到
SQLSTATE[HY000] [2006]类错误 - 调用
$connection->close()清除旧 PDO 实例 - 调用
$connection->initConnect(true)强制重建连接 - 重放原 SQL(仅一次,不递归重试)
注意:重连成功后下一条查询才能继续,当前这次请求仍会返回错误响应。日志里看到两次查询记录(失败 + 成功),说明它确实工作了。
高并发或 Swoole 环境下 break_reconnect 为何无效
因为它的设计基于「每次 HTTP 请求新建连接对象」模型,而长生命周期环境破坏了这个前提:
- Swoole 常驻进程复用同一个
Connection实例,但break_reconnect只作用于单次请求上下文 - 连接池中获取的连接可能已被其他请求用过,
initConnect(false)不检测存活,直接复用已断开的句柄 - 此时必须手动探测:在
Db::event('before_execute')里调用$pdo->getAttribute(PDO::ATTR_SERVER_INFO),捕获异常后close()+initConnect(true)
事务内连接断开只能自己兜底
框架明确放弃在事务中重连,这是有意为之的安全限制。一旦 startTrans() 后连接中断,rollback() 都可能失败。可靠做法是:
- 把关键操作拆成独立事务,降低单事务耗时
- 用
try/catch包裹整个事务块,失败后 sleep 100ms 再重试(最多 2~3 次) - 重试前必须调用
Db::getConnection()->close(),否则下次initConnect(true)可能复用坏连接 - 每次重试都重新调用
Db::transaction(),不能复用已 rollback 的事务上下文
真正容易被忽略的是:重连不等于连接恢复,它只是让下一次查询有机会成功;而事务的原子性要求你必须从头再来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











