CodeIgniter 中 error_get_last 无效因框架拦截错误;CI3 的 reconnect 配置仅对旧 mysqli 有效,需手动 safe_query 捕获 2006/2013 错误并重连;CI4 支持 ping 和 tryReconnect 但需手动调用,且 DB 超时配置须与应用匹配。

error_get_last 在 CodeIgniter 中基本无效,不是因为你写错了,而是框架接管了错误处理流程——它把 PHP 原生错误拦截、封装、转成日志或 500 页面,error_get_last 拿不到被吞掉的底层错误。所以别指望靠它判断数据库断连;得从连接层本身下手。
CodeIgniter 3 的 $db['default']['reconnect'] = TRUE 是个假开关
CI3 的数据库配置里确实有 reconnect 这个键,但官方文档没说清:它只在 mysqli 驱动下对「查询执行中连接意外中断」起作用,且仅限于 mysql_connect() 已废弃的旧模式;现代 mysqli 或 PDO 实际上根本不走这个逻辑。开启后也不会自动重试 SQL,只是下次调用 $this->db->query() 时尝试重建连接——前提是上一次连接已明确失效(比如超时后首次 query 报错),而不是实时探测。
常见误判现象:
- 连接空闲超时(如 MySQL
wait_timeout=28800)后,第一次 query 报MySQL server has gone away,但第二次就恢复了——这不是重连生效,是 CI 内部检测到连接失效后新建的 - 你在事务中执行多条语句,中间连接断了,
reconnect=TRUE不会帮你续上事务,只会让后续语句报错
CI3 真正可用的重连方案:手动包装 query + 捕获特定错误码
CI3 没提供钩子拦截连接异常,只能在业务层补救。核心思路是:捕获 2006(server has gone away)、2013(lost connection)这类错误,主动 close 当前连接,再触发一次 query。
实操建议:
- 在模型基类或公共 helper 里写一个
safe_query($sql)方法,内部 try/catchmysqli错误码 - 遇到
2006或2013时,先调用$this->db->close(),再执行$this->db->reconnect()(注意:这个方法存在但不保证成功,需配合重试) - 最多重试 1–2 次,避免死循环;重试前加
usleep(50000)避免雪崩 - 不要在事务中用这套逻辑——事务状态无法跨连接延续
示例片段:
public function safe_query($sql)
{
$result = $this->db->query($sql);
if ($result === FALSE && in_array($this->db->error()['code'], [2006, 2013])) {
$this->db->close();
$this->db->reconnect();
return $this->db->query($sql);
}
return $result;
}
CI4 原生支持连接健康检查,但默认不启用
CI4 的 Database 类内置了 isValidConnection() 和 ping(),但不会自动触发。你得在关键操作前手动 ping,或者用 tryReconnect() 显式干预。
推荐做法:
- 在 BaseController 的
initController中,对读操作(如get()、find())前加if (!$this->db->isConnected() || !$this->db->ping()) { $this->db->reconnect(); } - 写操作(
insert()、update())建议跳过 ping,直接执行,失败后再按错误码重试——因为 ping 本身也是一次网络往返,反而增加延迟 - 配置项
$db['default']['DBDebug'] = false在生产环境必须关掉,否则连接失败时会暴露敏感信息
真正容易被忽略的一点:MySQL 的 wait_timeout 和 interactive_timeout 必须和应用层重连策略匹配。如果设成 60 秒,而你的请求平均间隔 90 秒,那每次都要重连——这不是框架问题,是 DB 配置没对齐。先看 SHOW VARIABLES LIKE '%timeout%',再决定要不要调高,而不是堆重连逻辑。


















