thinkphp5默认不重连,break_reconnect仅在查询执行中遇2006错误时静默重试一次,且仅对非事务查询生效;它不适用于连接建立失败、事务内断线或非pdo_mysql驱动场景。

直接说结论:ThinkPHP5 默认不重连,break_reconnect 配置只在查询执行中报 2006 MySQL server has gone away 时静默重试一次,且仅对非事务查询有效;它不是“连接前自动检测”,也不是“失败后无限重试”,更不适用于连接建立阶段失败的场景。
为什么 break_reconnect 设了却没用?
常见现象是加了 'break_reconnect' => true,但日志里还是频繁出现 PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away。根本原因有三个:
-
break_reconnect只在query()或execute()执行过程中抛出 PDO 异常时触发,而连接初始化失败(如Connection refused)完全绕过该逻辑 - 未设置
'params' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],导致异常被静默吞掉,isBreak()根本没机会运行 - 用了
mysqli或其他非pdo_mysql驱动,该配置对 PDO 外的驱动基本无效
CLI/队列任务必须手动探活
长驻进程(如 php think queue:work)启动后只建一次连接,MySQL 的 wait_timeout(默认 8 小时)一到,连接就被服务端踢掉,但 PHP 进程毫无感知。等到下次查库才暴露问题。
- 不要依赖
break_reconnect等报错再救——第一次失败已影响业务 - 推荐在任务开头加轻量探测:
Db::getPdo()->exec('SELECT 1'),捕获异常后立即Db::close()+Db::connect() - 若在事务中执行此探测,会破坏事务一致性,必须避开事务上下文
- 对于 Swoole 或多进程 CLI 场景,每个子进程需独立管理连接生命周期,不能复用父进程的
Db实例
事务中重连等于放弃一致性
一旦在 Db::transaction() 内部发生断线,break_reconnect 不生效,且重连后原事务已丢失。此时继续执行会报 There is no active transaction 或写入脏数据。
- 事务内不允许自动重连,框架设计上就禁止了该行为
- 关键操作(如支付回调、库存扣减)需业务层手动封装重试:每次失败后
Db::startTrans()新启事务,而非复用旧引用 - 重试次数建议 ≤3 次,间隔用
usleep(100000),避免雪崩;最后一次失败必须原样抛出,不可静默吞掉 - 不要在事务块里调用
Db::close()—— 它不会回滚当前事务,只会让后续rollback()也失败
最易被忽略的一点:所有重连逻辑都建立在「连接对象可被替换」的前提下。ThinkPHP 的 Db 是单例,Db::close() 只清空内部 $linkID,下一次 query() 会重建;但如果你缓存了 $db = Db::name('user') 并反复调用,这个实例仍持有失效连接引用,必须重新获取或强制刷新。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











