数据库连接池泄漏排查需三步联动:先通过HikariCP的leakDetectionThreshold配置(如15000ms)触发堆栈日志精准定位泄漏行号;再用jstack区分RUNNABLE/TIMED_WAITING/WAITING线程状态判断泄漏类型;最后检查ResultSet/Statement未关闭、try-with-resources不完整及事务内异步调用等高频疏漏点。

Java 中 JDBC 连接泄漏排查不是靠猜,而是靠“让连接自己说话”——通过连接池的主动检测、线程状态分析和代码验证三步联动,快速定位到哪一行没关连接。
开启 HikariCP 泄漏检测日志
HikariCP 是当前主流连接池,它不依赖外部工具就能直接暴露泄漏点:
- 配置 leakDetectionThreshold(单位毫秒),例如设为 15000,表示连接被借出超 15 秒未归还即触发告警
- 默认值是 0(关闭),生产环境建议设为 30–120 秒;测试环境可更激进(如 5000),提前暴露问题
- 触发后会打印完整堆栈,精准到源码行号:at com.example.service.OrderService.createOrder(OrderService.java:32) ——这就是 getConnection() 执行了,但后续没 close 的位置
用 jstack 区分线程卡点类型
日志告诉你“谁漏了”,jstack 告诉你“为什么漏”:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- RUNNABLE 状态卡在 socketRead0 或 executeQuery:连接已发出 SQL,但执行卡住或没走到 close,常见于慢查询、死锁或遗漏 finally 关闭
- TIMED_WAITING 卡在 sleep / Feign / OkHttp 调用:事务内调了外部服务,事务未提交,连接被长期占用
- WAITING 卡在 HikariPool.getConnection:这是结果,说明上游已有连接未归还,下游只能排队等待
检查三类高频关闭遗漏点
90% 的泄漏藏在看似“没问题”的代码细节里:
立即学习“Java免费学习笔记(深入)”;
- ResultSet 和 Statement 没关:只 close(Connection) 不够,JDBC 规范要求三者都显式释放,尤其 ResultSet 在大数据量时会持服务端游标
- try-with-resources 写法不完整:比如只把 Connection 放入 try,而 Statement 在外面创建 → 它不会自动关闭
- @Transactional 方法里起新线程或发 MQ:事务上下文未传播,导致连接无法随事务结束释放
在单元测试中拦截泄漏
别等上线才救火,把泄漏堵在 CI 流水线里:
- 每个集成测试前后统计活跃连接数,测试结束断言 activeConnections == 0
- 搭配 Testcontainers 启动真实数据库,模拟真实连接行为
- 启用 HikariCP 的 initializationFailTimeout = -1,让连接池初始化失败时直接抛异常,避免带病启动

















