最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
PHP7.0连接数据库时如何处理连接失败重试
时间:2026-07-15 19:44:01 编辑:袖梨 来源:一聚教程网
连接失败重试需手动实现,非框架默认行为;必须开启PDO异常模式、新建连接对象、避免雪崩重连,事务中需重建事务上下文,长连接场景应优先健康检查而非重试。
连接失败重试不是框架默认行为,必须手动控制
ThinkPHP 或原生 PDO/mysqli 都不会在连接失败后自动重试。所谓“重试”是业务层逻辑,不是底层驱动能力。你写的 Db::connect() 或 new PDO() 失败了,就真的失败了——除非你自己包一层 try/catch 并重试。
常见错误现象:代码里写了 'break_reconnect' => true 却没生效;或用 Swoole 长连接时,连接断开后请求直接 500;又或者事务中报 MySQL server has gone away 后没重连就抛异常。
- 重试只对网络类错误(如连接拒绝、超时、
SQLSTATE[HY000] [2006])有意义,语法错误或主键冲突重试毫无作用 - 最多试 2~3 次,第 1 次失败后
usleep(100000)(100ms),避免雪崩式重连 - 每次重试都必须新建连接对象,不能复用已失败的
$pdo或$conn - 若用连接池或 Swoole,
break_reconnect基本失效,得监听onClose事件手动重建
PDO 连接失败重试要先确保异常模式开启
PDO::ATTR_ERRMODE 必须设为 PDO::ERRMODE_EXCEPTION,否则连接失败只返回 false,catch 根本捕不到异常,重试逻辑形同虚设。
典型配置漏项:charset=utf8mb4 写在 DSN 里,但 PDO::ATTR_ERRMODE 没设;或用了 mysql:host=localhost,结果 PHP 尝试走 Unix socket 却路径不对,报错 No such file or directory,你以为是密码错,其实只是 host 解析问题。
立即学习“PHP免费学习笔记(深入)”;
- DSN 中显式写
mysql:host=127.0.0.1;port=3306;,绕过 localhost → socket 的歧义 - Unix socket 场景下,DSN 应为
mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=test - MySQL 8.0+ 用户需确认认证插件兼容性,
caching_sha2_password会导致 PDO 连接失败且不报具体原因
事务内重试必须重新开启事务,不能复用上下文
事务中连接断开,框架会自动 rollback,但事务状态已破坏。此时若直接重试原 Db::transaction() 回调,会报 There is no active transaction。
正确做法是把整个事务逻辑包进循环,每次失败都新建事务上下文。
for ($i = 0; $i < 3; $i++) { try { Db::transaction(function () { Db::table('order')->where('id', 123)->update(['status' => 'paid']); }); break; } catch (thinkdbexceptionPDOException $e) { if ($i === 2) throw $e; usleep(100000); }}
- 不要在事务回调里做重试,那只是重试 SQL,不是重试连接
- ThinkPHP 的
break_reconnect在事务中不触发重连,它只作用于单条查询执行前的连接探活 - 如果用原生 PDO,
$pdo->beginTransaction()和$pdo->commit()也得在每次循环里重新调用
Swoole 或常驻进程环境下,连接健康检查比重试更重要
PHP-FPM 场景下每次请求都是新进程,连接失败重试尚可接受;但在 Swoole Worker 或 Laravel Octane 中,一个连接复用几十秒甚至几分钟,break_reconnect 不起作用,靠重试反而掩盖真实问题。
真正该做的是:连接空闲超 30 秒后主动 ping,失败则 close 并重建;或在每次查询前加 $pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS) 判断是否活跃(部分驱动支持)。
- 别依赖
mysqli_ping(),它在某些 MySQL 版本和 mysqli 驱动组合下返回 true 却实际不可用 - 更可靠的方式是执行一条轻量 SQL,如
SELECT 1,并设置PDO::ATTR_TIMEOUT防卡死 - 长连接场景下,
wait_timeout和interactive_timeoutMySQL 参数必须与应用层探活间隔匹配,否则刚 ping 完就断
wait_timeout、Swoole 的 worker_num、以及你自己的业务 SLA 里。
相关文章
- 逆战未来枪械大全 逆战未来枪械稀有度等级与获取方式详解 07-19
- 逆战未来新手攻略 逆战未来萌新入门避坑指南 07-19
- "无醇啤酒"是完全不含酒精吗 蚂蚁庄园1月17日答案早知道 07-19
- "太常寺"是古代掌管什么事务的机构 蚂蚁新村1月16日答案 07-19
- 四川名菜"开水白菜"就是用开水炖白菜吗 蚂蚁庄园1月17日答案早知道 07-19
- 蚂蚁新村今天正确答案1.16 07-19