跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Laravel如何做数据库连接超时重试次数_LaravelPDO重连策略配置【方法】

Laravel 不自动重连 MySQL,需手动配置 PDO 选项并调用 DB::purge() + DB::reconnect() 清除失效连接;重试仅对 SQLSTATE[2013]/[2006] 有效,且应避免在事务或模型事件中调用。 MySQL 连接超时后 Laravel 不自动重连?
PDO::ATTR_ERRMODE
和
DB::reconnect()
都不管用 默认情况下,Laravel 不会在查询失败时自动重试连接。哪怕你设置了
options
里的
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
,它也只是抛异常,不会重连。真正触发重连的时机,是下一次请求到来、连接被检测为“断开”时——但这个检测本身依赖于
DB::reconnect()
或底层驱动的健康检查逻辑,而默认配置里压根没开。 必须手动在
config/database.php
的 MySQL 配置中添加
'options' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
,否则连接异常会被静默吞掉 启用重连需显式设置
'options' => [PDO::ATTR_EMULATE_PREPARES => true]
(部分版本兼容需要),否则预处理语句可能卡死连接 更关键的是加
'options' => [PDO::ATTR_TIMEOUT => 5]
,让底层 PDO 在握手阶段就超时,避免挂起等待 不要指望
DB::reconnect()
被自动调用;它只在你手动调用或某些中间件里才生效,不是兜底机制 Laravel 9+ 中如何配置连接池级重试次数?
retry_after
和
retry_times
不是数据库配置项
retry_after
和
retry_times
是队列任务的配置,和数据库连接完全无关。数据库层的重试必须靠封装逻辑或扩展连接器实现,不能靠 config 文件一键开启。 真正的重试控制点在
Illuminate\Database\Connectors\MySqlConnector
类的
connect()
方法里,但它不暴露重试参数 若想在连接建立失败时重试,得自己写一个继承自
MySqlConnector
的类,并重写
connect()
,用
for
循环 +
try/catch
包裹
parent::connect()
注意:重试不能无脑循环,要配合
usleep(100000)
(100ms)避免雪崩,且最多 3 次——再多次大概率是网络或 DB 问题,不是临时抖动 别在
DB::transaction()
内部做重试,事务上下文里重连会导致
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
无法恢复 为什么
DB::connection()->getPdo()
报
Connection refused
后,后续查询仍失败? 因为 Laravel 的连接对象是单例缓存的,
getPdo()
返回的是已失效的 PDO 实例指针,不是新连接。即使你 catch 到异常并调用
DB::reconnect()
,也只重置了连接器内部状态,未刷新当前连接实例上的 PDO 对象。 Laravel 13.2.0 PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。 下载 最稳妥做法是:捕获
Illuminate\Database\QueryException
或
PDOException
后,立即执行
DB::purge('mysql')
清除连接缓存,再调用
DB::reconnect()
如果用了读写分离,记得对
'read'
和
'write'
分别 purge,否则只清主库连接,从库仍报错 不要在模型的
boot()
或
creating
事件里做 reconnect —— 此时连接尚未初始化,会触发
InvalidArgumentException: Database connection [xxx] not configured.
测试时用
tcpkill -i lo port 3306
模拟断连比改 timeout 更真实,避免误判重试逻辑是否生效 生产环境要不要开连接重试?
DB::listen()
日志里频繁出现
SQLSTATE[HY000] [2002] Connection refused
要看错误类型。如果是
[2002] Connection refused
,说明 Laravel 根本连不上 MySQL 进程,重试只是把失败延迟几秒;如果是
[2013] Lost connection to MySQL server during query
,才是典型的网络抖动或 wait_timeout 触发,这时重试才有意义。 线上建议只对
[2013]
和
[2006]
错误码做重试,其他一律快速失败,避免掩盖真实部署问题 用
DB::listen()
记录所有慢查询和连接异常,但别在监听回调里做重试操作——它运行在查询生命周期内,干扰执行流 连接池大小(
'pool' => ['min_connections' => 5, 'max_connections' => 20]
)比重试更重要;连接不够用时,重试只会加剧排队 真正容易被忽略的是 MySQL 的
wait_timeout
和 Laravel 的
lifetime
是否匹配;设成 60 秒却让连接池 idle 120 秒,必然断连,重试解决不了根本

相关文章