java排查连接池泄漏需启用泄漏检测机制:hikaricp设leak-detection-threshold(如30秒)捕获借出超时堆栈;druid需同时开启remove-abandoned、log-abandoned等参数检测空闲超时;先排除oracle半开连接、mysql超时配置冲突、异步线程未传播事务等假泄漏。

Java 中排查连接池连接泄露,核心是启用并善用连接池自带的泄漏检测机制,而不是靠人工盯日志或猜代码。不同连接池实现方式略有差异,但思路一致:让连接池在连接被借出超时未归还时主动告警,并附带调用栈,直指问题代码行。
HikariCP 和 Druid 是主流选择,下面分场景说明关键操作。
HikariCP 的 leak-detection-threshold 必须配且要合理
HikariCP 不会默认开启泄漏检测,leak-detection-threshold 默认为 0(禁用)。必须显式设置一个毫秒值,比如:
spring:
datasource:
hikari:
leak-detection-threshold: 30000 # 30秒
这个值不是越小越好。它应略大于你系统中最长的正常 SQL 执行时间(含网络延迟),常见设为 30–60 秒。设太小会导致误报(如慢查询、网络抖动);设太大则漏检。
一旦触发,日志会出现类似内容:
WARN com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detected. The connection ... has been in use for 30000ms. at com.example.order.service.OrderService.createOrder(OrderService.java:45) at com.example.order.controller.OrderController.submit(OrderController.java:22)
⚠️ 注意:该堆栈是连接被借出时的调用点,不是 close() 缺失的位置。它告诉你“谁借走的”,再顺藤摸瓜检查该方法里是否所有路径都确保归还(尤其是异常分支)。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
Druid 的 remove-abandoned 需配合 log-abandoned 才有用
Druid 的泄漏检测依赖三个参数协同工作:
spring.datasource.druid.remove-abandoned=true spring.datasource.druid.remove-abandoned-timeout=300000 # 5分钟 spring.datasource.druid.log-abandoned=true # 关键!不加这句只回收不打堆栈
log-abandoned=true 是定位根源的开关。开启后,一旦某连接空闲超时(注意:Druid 检测的是“空闲超时”,不是“借用超时”),它会打印完整堆栈,指出该连接最初是在哪创建/获取的。
适用于排查那些“取了连接但没用就丢了”的场景,比如 try 块里 getConnection() 后直接 return,忘了 close;或在 if 分支里获取连接,else 分支没覆盖。
真正定位前,先确认是不是“假泄漏”
有些情况看起来像泄漏,实则是其他问题:
- Oracle 场景下,
connection.close()只是标记可复用,若网络半开或驱动缓存未清,连接可能无法真正归还; - MySQL 的
wait_timeout(默认 8 小时)与连接池max-lifetime不匹配,导致连接在池中“假活”,被 Hikari 认为还在用; - 使用
@Async或线程池异步执行数据库操作,但事务上下文未传播,close()在错误线程执行或被跳过; - 手动调用
DriverManager.getConnection()绕过连接池,这类连接完全不受池管理,也不会被检测到。
所以看到泄漏告警,别急着改业务代码,先查:
- 数据库侧
SHOW PROCESSLIST,看是否有大量Sleep状态且Time很大的连接; - 应用进程 socket 数(
lsof -p <pid> | grep IPv4 | wc -l</pid>)是否持续增长; - JVM 堆外内存 RSS 是否同步上涨(指向底层 socket 缓冲区未释放)。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










