break_reconnect必须显式设为true且配合PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION才生效,否则错误被静默吞掉;事务中完全失效,需手动重试并重新开启事务。

break_reconnect 必须显式设为 true,否则断开后直接抛异常,不重连。
为什么开了 break_reconnect 还是报 “MySQL server has gone away”?
常见原因不是配置没写,而是它只在 PDO 抛出异常时触发,而 PDO 默认不抛异常。必须确保 PDO::ATTR_ERRMODE 被设为 PDO::ERRMODE_EXCEPTION,否则错误被静默吞掉,break_reconnect 根本没机会运行。
ThinkPHP8 的默认行为是:如果 config/database.php 里没显式配置 params,就不会设置这个属性;哪怕你写了 break_reconnect => true,也无效。
- 检查你的数据库配置中是否包含:
'params' => [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION] - 不要依赖
.env文件覆盖params,它不支持嵌套数组,会丢掉ATTR_ERRMODE - 如果用的是 Swoole 或协程环境,PDO 原生异常机制可能被绕过,此时
break_reconnect不生效,需手动监听连接关闭事件
break_reconnect 在事务里完全失效
这是最容易被忽略的致命点:一旦你在事务中执行 SQL 时连接断开,框架不会重连,而是直接回滚并抛出异常。重连机制只对非事务上下文的单次查询/执行有效。
立即学习“PHP免费学习笔记(深入)”;
事务内出错后,原事务已销毁,后续任何 Db::commit() 或 Db::rollback() 都会报 There is no active transaction。
- 关键操作若需强一致性 + 容错,必须自己封装重试逻辑,且每次重试都要重新调用
Db::transaction() - 不能把整个事务块包进
try/catch然后循环重试——那样只是反复尝试开启一个已损坏的事务上下文 - 重试前加
usleep(100000),避免瞬时重连雪崩;最多试 2~3 次,再失败就该告警而不是硬扛
CLI 场景下怎么安全启用断线重连?
Web 请求(如 FPM)和 CLI(如队列、定时任务)共用同一份数据库配置时,break_reconnect => true 在 Web 环境反而危险:事务中断后自动重连可能破坏数据一致性,且掩盖连接泄漏问题。
推荐做法是按运行环境动态覆盖配置:
- 在队列命令入口(如
app/command/QueueWork.php)中手动初始化连接:Db::init(array_merge(config('database.'), ['break_reconnect' => true])) - 或在
think queue:work启动前通过环境变量区分:QUEUE_ENV=cli php think queue:work,然后在配置文件中做判断 - 避免全局开启,尤其当项目同时跑支付回调(需事务)和日志归档(可容忍重试)时,混用配置极易引发数据错乱
真正稳的不是“不断线”,而是“断了也能可控恢复”。break_reconnect 只解决单次查询失败后的补救,它不保活、不探活、不清理旧连接。生产环境必须配合连接池健康检查或任务开头主动 Db::query('SELECT 1') 探活,否则第一次失败永远逃不掉。


















