报错信息:13:02:56.239 [http-nio-8080-exec-1] WARN o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - [logException,208] - Resolved [org.springframework.dao.RecoverableDataAccessException: ### Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failureThe last packet successfully received from the server was 52,773 milliseconds ago. The last packet sent successfully to the server was 52,785 milliseconds ago.### The error may exist in file [C:\alibaba\man-service\Man-service\target\classes\mapper\mine\MineMapper.xml]### The error may involve com.ruoyi.man.mine.mapper.MineMapper.selectMineList-Inline### The error occurred while setting parameters### SQL: select id, big_name, shi_name, xian_name,qymc, tyshdm acc_test### Cause:
报错界面:

一、报错核心含义
RecoverableDataAccessException | Spring 封装的 “可恢复数据访问异常”,说明是数据库连接层面的问题(非 SQL 语法错误),可通过重试 / 重连恢复 |
Communications link failure | MySQL JDBC 驱动抛出的核心错误:应用与 MySQL 服务器之间的 TCP 连接已断开,无法收发数据包 |
last packet 52,773ms ago | 最后一次成功和 MySQL 交互是 52 秒前,说明连接因 “长时间空闲” 被断开,执行查询时用了失效的 “死连接” |
error may involve MineMapper.selectMineList | 触发报错的业务操作是执行selectMineList查询(仅为 “触发点”,非报错根源) |
while setting parameters | 连接断在 “SQL 参数绑定阶段”,并非 SQL 语法 / 参数错误,只是恰好执行到这一步时连接失效 |
二、典型判断
通过报错特征快速锁定大概率问题:
- 看 “last packet” 时间:
- 时间在 “几十秒~几小时”:90% 是「MySQL 空闲连接超时 + 连接池未配置保活」;
- 时间为 “0ms”:网络不通 / MySQL 宕机 / 端口被拦截;
- 看报错频率:
- 偶发(每天 1~2 次):网络波动 / 连接池保活配置不足;
- 必现(每次执行都报错):MySQL 服务宕机 / 防火墙拦截 / 连接 URL 错误;
- 看 SQL 提示:
- 若仅提示 “setting parameters”:优先排查连接问题,而非 SQL 本身;
- 若伴随 SQL 语法报错:再验证 SQL 字段 / 参数是否合法;
- 看环境特征:
- 测试环境 / 低访问量服务:大概率是 “空闲连接被 MySQL 断开”(低访问导致连接长期空闲);
- 高并发环境:大概率是 “MySQL 连接数耗尽”。
三、常见的错误场景
场景 1:MySQL 空闲连接超时参数过小(最常见)
- 原理:MySQL 有
wait_timeout(非交互式连接超时,默认 8 小时,常被误改为 30 秒 / 60 秒),超过该时间的空闲连接会被 MySQL 主动断开;但应用连接池未感知,仍向业务返回 “死连接”。 - 典型特征:服务启动后首次访问正常,空闲一段时间(如 1 分钟)后首次访问报错,刷新后恢复。
场景 2:数据库连接池未配置 “保活 / 重连” 机制
- 原理:连接池(Druid/HikariCP)未开启 “空闲连接检测”,无法识别并剔除被 MySQL 断开的死连接;或连接池空闲超时大于 MySQL 的
wait_timeout,导致死连接长期留存。 - 典型特征:偶发报错,无规律,重启应用后暂时消失。
场景 3:网络 / 防火墙拦截 TCP 连接
- 原理:
- 应用服务器与 MySQL 服务器之间的防火墙 / 安全组拦截 3306 端口;
- 路由器 / 交换机开启 “空闲连接超时”,主动断开长时间空闲的 TCP 连接;
- 云服务器(如阿里云 RDS)的网络波动 / 跨可用区延迟过高。
- 典型特征:报错时伴随
ping MySQL_IP丢包,或telnet 3306不通。
场景 4:MySQL 连接数耗尽
- 原理:MySQL
max_connections(默认 151)被占满,新连接无法创建,旧连接因竞争被强制断开;或应用未释放连接(如未关闭 Statement/ResultSet),导致连接泄露。 - 典型特征:高并发时段集中报错,
show processlist显示Threads_connected接近max_connections。
场景 5:MySQL 服务宕机 / 重启
- 原理:MySQL 因 OOM、配置变更、人工重启等原因停止 / 重启,应用连接池中的所有连接失效,执行查询时触发链路失败。
- 典型特征:某一时间点后所有访问都报错,MySQL 日志有重启记录。
场景 6:SQL / 参数问题(次要触发点)
- 原理:SQL 语法错误(如字段间少空格
xian_name,qymc)、参数类型不匹配,执行时触发异常,叠加连接轻微不稳定时放大为链路失败。 - 典型特征:修改 SQL 后报错消失,或直接执行 SQL 时提示语法错误。
四、分场景处理办法
紧急处理(5 分钟恢复服务)
- 重启应用:清空连接池中的死连接,重新创建有效连接(临时解决);
- 检查 MySQL 状态:
- Windows:
services.msc查看 MySQL 服务是否运行; - Linux:
systemctl status mysqld,宕机则执行systemctl restart mysqld;
- Windows:
- 测试网络连通性:
不通则关闭防火墙 / 配置安全组放行;ping 你的MySQL_IP # 测试网络可达性 telnet 你的MySQL_IP 3306 # 测试3306端口是否开放 - 临时调整 MySQL 超时:登录 MySQL 执行:
set global wait_timeout=7200; # 临时设为2小时 set global interactive_timeout=7200;
永久修复(按场景对应)
| 错误场景 | 具体修复措施 |
|---|---|
| 场景 1:MySQL 超时过小 | 1. 修改 MySQL 配置文件(my.ini/my.cnf):[mysqld]wait_timeout = 7200interactive_timeout = 72002. 重启 MySQL 使配置生效; |
| 场景 2:连接池未保活 | 以 Druid 为例(Ruoyi 框架常用):yaml<br>spring:<br> datasource:<br> druid:<br> url: jdbc:mysql://IP:3306/库名?autoReconnect=true&serverTimezone=GMT%2B8<br> # 保活核心配置<br> time-between-eviction-runs-millis: 60000 # 每分钟检测一次空闲连接<br> test-while-idle: true # 空闲时检测连接有效性<br> min-evictable-idle-time-millis: 3600000 # 1小时(小于MySQL的2小时)<br> validation-query: SELECT 1 # 检测连接的SQL<br>以 HikariCP 为例:yaml<br>spring:<br> datasource:<br> hikari:<br> idle-timeout: 3600000<br> connection-test-query: SELECT 1<br> leak-detection-threshold: 60000<br> |
| 场景 3:网络 / 防火墙拦截 | 1. 开放 MySQL 服务器 3306 端口(防火墙 / 安全组);2. 禁用网络设备的 “空闲连接超时”;3. 云数据库开启 “内网访问”,避免公网波动; |
| 场景 4:连接数耗尽 | 1. 临时调整:set global max_connections=500;2. 永久调整:my.ini/my.cnf 添加max_connections=500;3. 排查应用连接泄露:关闭未释放的 ResultSet/Statement,使用连接池监控; |
| 场景 5:MySQL 宕机 / 重启 | 1. 配置 MySQL 自动重启(systemctl enable mysqld);2. 应用层添加数据库重连重试逻辑(如 Spring Retry);3. 监控 MySQL 状态,宕机时告警; |
| 场景 6:SQL / 参数问题 | 1. 修正 SQL 语法(如字段间补空格);2. 验证参数类型匹配(如 String 对应 varchar,Long 对应 bigint);3. 直接在 MySQL 客户端执行 SQL,确认能正常返回; |
通用重试方案(应对偶发连接异常)
在业务代码中添加重试逻辑(Spring Retry),避免单次连接失败导致业务报错:
<!-- 引入依赖 -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
@Service
@EnableRetry // 开启重试
public class MineService {
@Retryable(
value = {RecoverableDataAccessException.class, CommunicationsException.class},
maxAttempts = 3, // 重试3次
backoff = @Backoff(delay = 1000) // 每次重试间隔1秒
)
public List<Mine> selectMineList(Mine mine) {
return mineMapper.selectMineList(mine);
}
// 重试失败后兜底
@Recover
public List<Mine> recover(Exception e) {
log.error("查询矿场列表失败", e);
return Collections.emptyList(); // 或抛自定义异常
}
}
五、避免方式(规范 + 监控)
1. 配置规范(从源头避免)
| 配置项 | 推荐值 | 说明 |
|---|---|---|
MySQL wait_timeout | 7200 秒(2 小时) | 避免过小导致空闲连接被频繁断开 |
连接池 min-evictable-idle-time-millis | 3600 秒(1 小时) | 必须小于 MySQL 的wait_timeout |
连接池 test-while-idle | true | 开启空闲连接检测,剔除死连接 |
| JDBC URL | 追加autoReconnect=true | 驱动自动重连失效连接 |
MySQL max_connections | 500(根据业务调整) | 避免高并发时连接数耗尽 |
2. 运维监控(提前预警)
- 监控 MySQL 关键指标:
Threads_connected(当前连接数):接近max_connections时告警;Aborted_connects(失败连接数):突增时排查网络 / 权限;
- 监控应用连接池指标:
- Druid:通过
http://ip:port/druid查看 “空闲连接数”“活跃连接数”,死连接数 > 0 时告警; - HikariCP:监控
idleConnections/activeConnections,异常时自动重启连接池;
- Druid:通过
- 网络监控:监控应用与 MySQL 之间的网络延迟 / 丢包率,超过阈值(如延迟 > 500ms、丢包 > 1%)告警。
3. 代码规范(避免连接泄露)
- 所有数据库操作使用
try-with-resources自动关闭资源:try (Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { // 业务逻辑 } catch (SQLException e) { // 异常处理 } - 避免 “长连接持有”:不要在单例 Bean 中持有数据库连接,每次操作都从连接池获取 / 归还;
- 高并发场景使用 “连接池隔离”:不同业务模块使用独立连接池,避免单模块耗尽所有连接。
4. 环境规范
- 测试 / 生产环境统一配置:避免测试环境改小
wait_timeout,生产环境未同步; - 云数据库适配:使用云厂商提供的连接池代理(如 RDS 读写分离代理),减少直连风险;
- 跨机房部署:应用与 MySQL 尽量同机房部署,避免跨机房网络波动。

6132

被折叠的 条评论
为什么被折叠?



