You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tomcat+HikariCP连接池耗尽:SQLTransientConnectionException问题求助

问题定位与解决方案:HikariCP连接池泄漏导致SQLTransientConnectionException

问题根源

你遇到的SQLTransientConnectionException(连接池无可用连接、请求超时),核心原因就是连接泄漏:getLatestModification方法中重复获取连接但未正确释放,导致取出的连接无法归还到HikariCP连接池。当所有10个连接都被占用且无法回收时,新的请求就会超时。

日志显示活动连接始终维持最大值、无空闲连接,完全符合连接泄漏的特征——连接被取出后没有被正确关闭,连接池无法复用这些连接。

解决方案

1. 严格规范资源管理,杜绝重复获取连接

每一次获取的Connection、Statement、ResultSet都必须用try-with-resources包裹,确保资源自动关闭。同时尽量复用同一个连接完成所有数据库操作,避免不必要的连接请求,降低泄漏风险。

错误代码示例(存在泄漏)

public Date getLatestModification() throws SQLException {
    // 未用try-with-resources包裹,连接无法自动归还
    Connection conn1 = dataSource.getConnection();
    Statement stmt1 = conn1.createStatement();
    ResultSet rs1 = stmt1.executeQuery("SELECT MAX(create_time) FROM table1");
    Date date1 = rs1.getDate(1);

    // 再次获取连接,同样未正确释放
    Connection conn2 = dataSource.getConnection();
    Statement stmt2 = conn2.createStatement();
    ResultSet rs2 = stmt2.executeQuery("SELECT MAX(update_time) FROM table2");
    Date date2 = rs2.getDate(1);

    // 手动关闭不彻底,conn1、conn2未关闭
    rs1.close();
    stmt1.close();
    rs2.close();
    stmt2.close();

    return date1.after(date2) ? date1 : date2;
}

修正后的代码

public Date getLatestModification() throws SQLException {
    // 复用同一个连接完成所有查询,减少连接获取次数
    try (Connection conn = dataSource.getConnection();
         Statement stmt1 = conn.createStatement();
         ResultSet rs1 = stmt1.executeQuery("SELECT MAX(create_time) FROM table1")) {
        
        Date date1 = rs1.next() ? rs1.getDate(1) : null;

        // 在同一个连接下执行第二个查询,无需重新获取连接
        try (Statement stmt2 = conn.createStatement();
             ResultSet rs2 = stmt2.executeQuery("SELECT MAX(update_time) FROM table2")) {
            
            Date date2 = rs2.next() ? rs2.getDate(1) : null;
            return (date1 != null && date1.after(date2)) ? date1 : date2;
        }
    }
    // try-with-resources会自动关闭所有资源(conn、stmt1、rs1、stmt2、rs2),无需手动关闭
}

如果业务逻辑必须分开获取连接(不推荐),也要确保每一次连接都被try-with-resources包裹:

public Date getLatestModification() throws SQLException {
    Date date1;
    try (Connection conn = dataSource.getConnection();
         Statement stmt = conn.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT MAX(create_time) FROM table1")) {
        date1 = rs.next() ? rs.getDate(1) : null;
    }

    Date date2;
    try (Connection conn = dataSource.getConnection();
         Statement stmt = conn.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT MAX(update_time) FROM table2")) {
        date2 = rs.next() ? rs.getDate(1) : null;
    }

    return (date1 != null && date1.after(date2)) ? date1 : date2;
}

2. 配置连接池泄漏检测,精准定位问题

在HikariCP的配置文件中添加泄漏检测阈值,当连接未归还超过指定时间时,会打印详细的堆栈信息,直接定位泄漏代码:

# 连接未归还超过2秒时打印泄漏堆栈
hikari.leakDetectionThreshold=2000

3. 验证修复效果

  • 重启服务后复现场景,查看日志确认是否还有泄漏堆栈输出。
  • 通过Tomcat管理页面或HikariCP的MBean监控连接池指标,确认请求结束后活动连接数回落、空闲连接数恢复正常。

内容的提问来源于stack exchange,提问作者qwhjrfbgeegbgwdv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:15:13