若依报错:CommunicationsException, druid version 1.2.16, jdbcUrl(Druid 连接池丢弃失效MySQL连接[discard])

报错界面:报错信息:

13:02:56.060 [http-nio-8080-exec-1] ERROR c.a.d.p.DruidPooledStatement - [errorCheck,370] - CommunicationsException, druid version 1.2.16, jdbcUrl : jdbc:mysql://10.xx.xx.xx:36060/test-man?useUnicode=true&xxxxxx, testWhileIdle true, idle millis 52779, minIdle 10, poolingCount 4, timeBetweenEvictionRunsMillis 60000, lastValidIdleMillis 52779, driver com.mysql.cj.jdbc.Driver, exceptionSorter com.alibaba.druid.pool.vendor.MySqlExceptionSorter

13:02:56.065 [http-nio-8080-exec-1] ERROR c.a.d.p.DruidDataSource - [handleFatalError,1954] - {conn-10005} discard

报错核心含义是 Druid 数据库连接池检测到失效 MySQL 连接并执行 “丢弃操作” 引发的错误,核心是「连接池内的空闲连接被 MySQL / 网络提前断开,Druid 未及时剔除,业务线程获取到死连接后触发通信异常」。

对应报错日志中关键信息可以一步步分析,ERROR c.a.d.p.DruidPooledStatement - [errorCheck,370] - CommunicationsException表示Druid 在执行 SQL 前检查连接有效性,发现连接已失效(TCP 链路断开),抛出 MySQL 通信异常

druid version 1.2.16这个版本为Druid稳定版,可以排除版本 BUG 导致的异常

jdbc:mysql://10.xx.xx.xx.33:36060/test-man?useUnicode=true&xxxxxx可以看出连接的 MySQL 地址 / 端口 / 库名/useSSL / 时区等配置都是规范的,URL 参数没得语法错误。

testWhileIdle true 已开启 “空闲时检测连接有效性”,但检测周期未到,未及时发现死连接

idle millis 52779表示该连接已空闲 52779 毫秒,远超 MySQL 默认 / 配置的空闲超时阈值

minIdle 10, poolingCount 4表示连接池配置 “最小空闲连接数 10”,但实际池内仅 4 个连接(资源不足),被迫复用失效连接

timeBetweenEvictionRunsMillis 60000 表示每 60 秒(1 分钟)检测一次空闲连接,连接空闲 52 秒时就被业务获取,检测 “滞后”

lastValidIdleMillis 52779 意思是最后一次验证该连接有效是 52 秒前,后续 MySQL 已主动断开此连接

DruidDataSource - [handleFatalError,1954] - {conn-10005} discard识别到 “致命连接错误”,执行 “丢弃该失效连接” 操作(保护机制,避免后续业务复用死连接)


通俗总结:连接池里的一个连接空闲了 52 秒,被 MySQL 主动断开,但 Druid 的空闲检测周期是 60 秒(还没到检测时间);同时连接池缺连接(配置最少 10 个,实际只有 4 个),业务线程只能拿这个死连接执行 SQL,触发通信异常,Druid 发现后立刻丢弃该连接。

核心判断

  1. 核心矛盾:Druid 的空闲检测周期(60 秒) > 连接实际空闲时长(52 秒),且 MySQL 的wait_timeout ≤ 52 秒 → 连接被 MySQL 断开后,Druid 未及时剔除;
  2. 资源层面:连接池minIdle配置过高(10),业务请求导致连接池资源耗尽(poolingCount=4),无法淘汰死连接,只能复用;
  3. 异常类型:属于 “空闲连接超时断开”(idle millis 52 秒),非突发网络中断 / MySQL 宕机(后者会显示 “last packet 0ms ago”);
  4. 责任边界:非 SQL 语法 / 驱动问题(报错无 SQL 相关提示),纯连接池 + MySQL 超时配置不匹配问题。

常见错误场景(按概率排序)

场景 1:MySQL 空闲超时配置过小(最核心)

  • 原理:MySQL 的wait_timeout(非交互式连接超时)被配置为≤52 秒(如 30 秒 / 60 秒),超过该时间的空闲连接会被 MySQL 主动断开;而 Druid 的检测周期是 60 秒,检测 “滞后”,没来得及剔除死连接;
  • 典型特征:服务启动后首次访问正常,空闲 50~60 秒后首次访问报错,刷新后恢复(Druid 已丢弃死连接并创建新连接)。

场景 2:Druid 连接池资源不足

  • 原理minIdle=10(期望最少保留 10 个空闲连接),但实际poolingCount=4(池内仅 4 个),连接池缺连接的原因:
    • 业务突发高并发,连接被耗尽;
    • 应用存在 “连接泄露”(未关闭 Statement/ResultSet,连接长期被占用);
  • 典型特征:高并发时段报错频繁,Druid 监控面板显示 “活跃连接数” 接近 “最大连接数”。

场景 3:Druid 检测参数配置不合理

  • 原理min-evictable-idle-time-millis(连接空闲多久被剔除)配置≥MySQL 的wait_timeout,导致死连接长期留存;
  • 典型特征:偶发报错,无规律,重启应用后暂时消失。

场景 4:网络设备空闲超时拦截

  • 原理:路由器 / 防火墙 / 云安全组配置了≤52 秒的 “TCP 空闲连接超时”,主动断开应用与 MySQL 的链路(非 MySQL 主动断开);
  • 典型特征:同网段其他应用连接该 MySQL 也会偶发通信异常,ping无丢包但telnet连接会随机断开。

处理办法(分紧急 / 永久)

紧急处理(5 分钟恢复服务)

  1. 重启应用:清空连接池内的死连接,重新创建有效连接(临时解决,治标);
  2. 临时调整 MySQL 超时:登录 MySQL 执行以下命令(立即生效,重启 MySQL 后失效):

    sql

    set global wait_timeout=7200;  -- 临时设为2小时,避免短时间断开
    set global interactive_timeout=7200;
    
  3. 临时调低 Druid 检测周期:修改应用配置文件,重启应用(让检测更频繁):

    yaml

    spring:
      datasource:
        druid:
          time-between-eviction-runs-millis: 30000  # 改为30秒检测一次
    

永久修复(按场景对应)

错误场景具体修复措施
场景 1:MySQL 超时过小1. 修改 MySQL 配置文件(my.ini/my.cnf):[mysqld]wait_timeout = 7200interactive_timeout = 72002. 重启 MySQL 使配置生效;3. 验证:show variables like 'wait_timeout';(确认值为 7200)
场景 2:连接池资源不足1. 调整连接池核心参数:yaml<br>spring:<br> datasource:<br> druid:<br> max-active: 50 # 最大连接数(根据QPS调整,默认20)<br> min-idle: 5 # 最小空闲连接数(降低至合理值,避免资源不足)<br> # 开启连接泄露检测<br> remove-abandoned: true<br> remove-abandoned-timeout: 180<br> log-abandoned: true<br>2. 排查连接泄露:检查代码是否未关闭 ResultSet/Statement(用 try-with-resources);
场景 3:Druid 检测参数不合理对齐 Druid 与 MySQL 超时配置(核心!):yaml<br>spring:<br> datasource:<br> druid:<br> # 连接空闲1小时后剔除(小于MySQL的2小时)<br> min-evictable-idle-time-millis: 3600000<br> # 每30秒检测一次空闲连接(小于空闲剔除时间)<br> time-between-eviction-runs-millis: 30000<br> # 检测连接有效性的SQL<br> validation-query: SELECT 1<br> validation-query-timeout: 3<br>
场景 4:网络设备拦截1. 联系运维 / 网管:关闭网络设备的 “TCP 空闲连接超时”,或设为≥7200 秒;2. 云数据库(如 RDS):开启 “内网访问”,避免公网设备拦截;3. JDBC URL 追加参数:autoReconnect=true&failOverReadOnly=false(驱动自动重连);

通用兜底方案(应对偶发异常)

在业务代码中添加重试逻辑,避免单次连接失效导致业务报错:

java

运行

@Service
@EnableRetry  // 开启重试
public class MineService {
    // 针对连接异常重试3次,间隔1秒
    @Retryable(
        value = {CommunicationsException.class},
        maxAttempts = 3,
        backoff = @Backoff(delay = 1000)
    )
    public List<Mine> selectMineList(Mine mine) {
        return mineMapper.selectMineList(mine);
    }

    // 重试失败后兜底
    @Recover
    public List<Mine> recover(CommunicationsException e) {
        log.error("查询失败:数据库连接失效", e);
        return Collections.emptyList(); // 或抛自定义业务异常
    }
}

避免方式

1. 配置规范(从源头避免)

配置项推荐值核心原则
MySQL wait_timeout7200 秒(2 小时)避免过小导致空闲连接被频繁断开
Druid min-evictable-idle-time-millis3600 秒(1 小时)必须 < MySQL 的wait_timeout
Druid timeBetweenEvictionRunsMillis30000 毫秒(30 秒)检测频率 < 空闲剔除时间,确保及时发现死连接
Druid minIdle5~10(根据 QPS 调整)避免配置过高导致连接池资源不足
Druid max-active50~100(高并发场景)满足业务峰值的连接需求
JDBC URL追加autoReconnect=true驱动层自动重连失效连接

2. 监控预警(提前发现问题)

  1. Druid 监控:开启 Druid 内置监控(http://应用IP:8080/druid),重点监控:
    • poolingCount(池内连接数):若持续 < minIdle,告警 “连接池资源不足”;
    • abandonedCount(泄露连接数):大于 0 时,排查代码连接泄露;
    • deadLockCount(死锁数):大于 0 时,优化 SQL / 事务;
  2. MySQL 监控
    • 监控Threads_connected(当前连接数):接近max_connections时告警;
    • 监控Aborted_connects(失败连接数):突增时排查网络 / 权限;
  3. 日志监控:在日志平台(ELK/Grafana)配置关键词告警:
    • 关键词:CommunicationsExceptiondiscardhandleFatalError
    • 触发条件:5 分钟内出现≥3 次,自动告警并执行 “连接池刷新”。

3. 代码规范(避免连接泄露)

  1. 所有数据库操作使用try-with-resources自动关闭资源:

    java

    运行

    try (Connection conn = getConnection();
         PreparedStatement ps = conn.prepareStatement(sql);
         ResultSet rs = ps.executeQuery()) {
        // 业务逻辑
    } catch (SQLException e) {
        log.error("数据库操作失败", e);
    }
    
  2. 避免 “长事务 / 长连接”:
    • 事务执行时长控制在 10 秒内,避免长期占用连接;
    • 不要在单例 Bean 中持有数据库连接(每次操作从连接池获取 / 归还)。

4. 运维规范

  1. 环境统一:测试 / 生产环境的 MySQL、Druid 配置保持一致(避免测试环境改小wait_timeout,生产未同步);
  2. 定期巡检:每周检查一次 Druid 监控和 MySQL 连接状态,清理无效连接;
  3. 云数据库适配:若使用 RDS / 云数据库,开启 “连接池代理”,由云厂商管理连接有效性。

总结

该报错的核心是「Druid 与 MySQL 的超时配置不匹配 + 连接池资源不足」,90% 的根因是 MySQLwait_timeout过小或 Druid 检测周期过长。

解决优先级:

  1. 紧急重启应用 → 临时恢复;
  2. 调整 MySQLwait_timeout和 Druid 检测参数 → 永久解决;
  3. 优化连接池配置 + 代码重试 → 兜底;
  4. 监控预警 → 提前发现问题。

按上述方案处理后,“连接失效 + discard” 的报错会彻底消失,同时连接池的稳定性大幅提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值