Yii2中MySQL服务器断开后如何实现原生重连?
Yii2 MySQL断线重连解决方案
原生实现说明
Yii2 从 2.0.36 版本开始,yii\db 组件原生支持 MySQL 断线自动重连能力,无需手动调用 close() 和 open() 方法。你之前手动调用未生效的核心原因是手动调用时机无法覆盖所有SQL执行前的节点,原生重连逻辑会在每次命令执行前自动检测连接有效性,失效则自动触发重连。
原生重连开启方式只需在数据库配置中添加 enableReconnect 参数即可,示例配置如下:
return [ 'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=127.0.0.1;dbname=你的数据库名', 'username' => '数据库账号', 'password' => '数据库密码', 'charset' => 'utf8mb4', // 开启原生断线自动重连 'enableReconnect' => true, // 可选配置:设置连接超时时间,配合重连逻辑使用 'attributes' => [ PDO::ATTR_TIMEOUT => 10, ], ], ], ];
注意:原生重连仅会在SQL执行前检测到连接断开时触发,若SQL执行过程中连接断开不会重连,避免重复执行写操作引发数据一致性问题。
低版本兼容方案
如果你使用的Yii2版本低于2.0.36,没有内置enableReconnect参数,可以通过继承原生Connection类自定义重连逻辑:
- 新增自定义连接类
<?php namespace common\components; use PDOException; use yii\db\Exception; class ReconnectableConnection extends \yii\db\Connection { // 最大重连次数,可根据业务调整 public $maxReconnectAttempts = 3; public function open() { $currentAttempt = 0; while (true) { try { parent::open(); break; } catch (PDOException $e) { $currentAttempt++; // 判定为连接断开类错误且未超过重试次数时,触发重连 if ( $currentAttempt <= $this->maxReconnectAttempts && (str_contains($e->getMessage(), 'MySQL server has gone away') || str_contains($e->getMessage(), 'Lost connection to MySQL server')) ) { $this->close(); // 等待100ms再重试,避免瞬间并发重试失败 usleep(100000); continue; } // 非连接类错误或超过重试次数,抛出异常 throw new Exception($e->getMessage(), $e->errorInfo, $e->getCode(), $e); } } } }
- 修改数据库配置中的
class参数为自定义类即可:
'db' => [ 'class' => 'common\components\ReconnectableConnection', // 其余原有数据库配置保持不变 ],
常见失效场景说明
- 常驻进程(如队列消费、Swoole服务)场景下不要开启
PDO::ATTR_PERSISTENT持久连接参数,持久连接的状态Yii2无法正常识别,会导致重连逻辑失效 - 手动事务执行过程中连接断开不会触发重连,事务上下文丢失后重连也无法恢复原有事务,此类场景需要自行捕获异常后手动回滚再重试
- 主库连接池配置本身不包含断线检测逻辑,需要配合上述重连参数一同使用才会生效
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

