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
相关产品推荐
相关产品推荐

