DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

HikariCP 长任务后 MySQL 通信失败:连接已借出却长时间没有 SQL

区分池内空闲和任务持有连接;核对会话与网络超时,避免用 maxLifetime 或自动重连掩盖事务边界问题。

长时间索引、导出或批处理运行一段时间后,MySQL JDBC 报 Communications link failure;错误里“最后一次收发数据”距离现在很久,但数据库的 wait_timeout 看起来仍然很大。使用 HikariCP 时,需要分清连接是在池内空闲,还是已经被任务借走、长时间没有执行 SQL。

本文针对后一种情况:任务取得连接后做大量计算、网络请求或文件处理,直到下一次 SQL 才发现连接失效。仅凭这个错误不能确认是 MySQL 主动关闭,也可能是代理、防火墙或其他网络故障。

对齐 SQL 空闲时间和连接持有时间

先保留异常时间、完整异常链,以及任务借出连接、最后一次 SQL、归还连接的时间。日志不要记录实际凭据或业务数据。应用仍在运算不代表数据库连接一直有流量;连接持有了半小时,期间没有 SQL,网络设备可能把它当作空闲连接。

在应用使用的 MySQL 会话中查看以下只读信息:

SELECT @@SESSION.wait_timeout, @@GLOBAL.wait_timeout;

会话值才对应这条连接。全局值用于新会话初始化,不能假定已有池连接跟着改变;交互式客户端的初始化方式也可能不同。还应核对数据库代理、负载均衡、防火墙的连接空闲限制,不能把 wait_timeout 当成整条网络路径唯一的计时器。

若断开总在接近同一段无 SQL 时长后出现,检查该时长是否对应某一层限制;这只是定位线索,需要服务端和网络侧记录支持。若错误发生在持续传输中,或时长没有稳定规律,则继续调查网络中断、实例重启及驱动异常。

另一个报错 Connection is not available, request timed out 表示等待池连接超时。任务长期占着连接也会导致这个现象,但它与已经借出的连接通信失败是不同阶段,不应只靠扩大连接池一起处理。

maxLifetime 不会强制替换任务手中的连接

HikariCP 的 maxLifetime 限制池连接寿命,但正在使用的连接不会被强制退休;通常等应用归还后才处理。keepaliveTime 只作用于池内空闲连接,不会给任务正在持有的连接做保活。

因此,把 maxLifetime 设得比网络超时短,可以帮助管理归还到池中的连接,却不能保证已经借出、长时间无 SQL 的连接不会断开。idleTimeout 也不是业务任务的 SQL 空闲超时。排查时先确认实际借还行为,再调整这些参数。

如果连接是在池内等待时失效,可根据数据库和网络的已知限制设置连接寿命与保活,满足当前 HikariCP 的参数约束。保留原配置,观察连接创建频率、池等待和数据库连接数;过于频繁地重建连接也有成本。需要回退时恢复原配置,并按应用实际方式重新加载。

把计算阶段移到取得连接之前

能拆开的任务,应先准备数据,到了需要执行 SQL 的短阶段再取得连接,用完及时关闭或归还。不要让连接跨越长时间外部请求、用户等待或文件处理。

如果必须使用事务,缩短持有连接的时间可能改变事务边界和一致性。先确定业务需要一次提交的范围,再设计分批提交、检查点与恢复机制;不能为了消除报错就把原来的一笔事务拆成任意多笔。

已经失效的连接不能继续承担原事务。通信中断时,应用可能无法判断最后一次写入或提交是否已成功。先停止使用该连接,按事务状态和业务记录核对结果;只有操作可安全重复、或者有幂等键等保障时,才能重试相应业务步骤。

不要直接打开 autoReconnect 并假定事务和会话状态会恢复。新连接无法自动还原旧连接的临时表、锁和所有事务上下文,也不证明可以再次执行上一次写入。

怎样确认修改针对了实际问题

重新运行原来的长任务,核对连接只在需要 SQL 的阶段被持有,任务不再在长时间无 SQL 后报通信失败。再检查任务的数据结果、事务边界和失败恢复行为,而不只看异常是否消失。

如果已缩短借出时间仍持续断开,应继续沿数据库、代理和网络记录定位。某次参数调整减少了异常,不足以证明所有通信失败都来自同一个空闲超时。