news 2026/5/15 13:36:37

数据库连接池泄漏:为什么连接越用越少?怎么彻底排查与修复?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据库连接池泄漏:为什么连接越用越少?怎么彻底排查与修复?

网罗开发(小红书、快手、视频号同名)

大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!


文章目录

  • 前言
    • 摘要
    • 描述:为什么连接池说我的连接泄漏了?
      • 什么叫连接泄漏?
    • 题解答案:如何彻底解决连接池泄漏?
      • 1. 使用 try-with-resources 自动关闭连接(最关键)
      • 2. 检查连接池最大连接数,避免业务量增长导致耗尽
      • 3. 开启 leakDetectionThreshold,让连接池自动“报警”
    • 代码解析:一个典型的泄漏案例(错误示例)
    • 正确示例 Demo:用 try-with-resources 自动关闭资源
    • 启用 leakDetectionThreshold:让 HikariCP 自动抓到泄漏点
    • 最大连接数问题:为什么连接泄漏看起来像“数据库压力太大”?
    • 实际场景分析:哪些地方最容易发生泄漏?
      • 场景 1:在循环中不断创建连接
      • 场景 2:异常抛出时 finally 被遗漏
      • 场景 3:使用多层封装(容易忘记关闭)
      • 场景 4:并发任务中手动开启连接,但不关闭
    • 示例测试与结果
    • 总结

前言

在后端项目里,数据库连接池泄漏几乎是所有人都踩过的坑。
一旦发生泄漏,症状非常典型:

  • 系统运行一段时间后请求突然变慢
  • 数据库连接数飙升到 max active
  • 错误日志出现 “Too many connections”
  • 必须重启服务才能恢复

最让人头疼的是:问题通常不是数据库本身,而是代码里有连接没被关闭—— 结果池子永远等不到归还,连接越用越少。

这篇文章我会讲清楚:

  1. 为什么连接池会泄漏
  2. 真实项目里的常见场景
  3. 如何让 HikariCP / DBCP 自动帮你找出泄漏点
  4. 可运行 Demo + 实战级代码解析

如果你也遇到过“线上数据库突然卡死,重启就好了”的情况,这篇文章非常值得收藏。

摘要

数据库连接池泄漏本质上是:连接被借出(getConnection)后没有被正确关闭(close)。
文章将从代码层面、连接池配置、监控机制三个角度来定位和解决问题。提供可运行 Demo(含 try-with-resources 正确写法!),以及 leakDetectionThreshold 和最大连接数配置的最佳实践。

描述:为什么连接池说我的连接泄漏了?

什么叫连接泄漏?

非常简单:
借出去的连接,没有再还回去。

连接池不是无限的,默认提供 10~50 个连接。如果你有一段代码没有关闭连接,那么每执行一次,连接池就少一个可用连接。

当连接数被占满后,后续请求就会卡死或直接报异常。

题解答案:如何彻底解决连接池泄漏?

解决方案大致分三步:

1. 使用 try-with-resources 自动关闭连接(最关键)

Java 中连接、Statement、ResultSet 都是 AutoCloseable,可以用 try-with-resources 自动 close。

2. 检查连接池最大连接数,避免业务量增长导致耗尽

例如 HikariCP 的maximumPoolSize,太小容易阻塞,太大又浪费资源。

3. 开启 leakDetectionThreshold,让连接池自动“报警”

这是 HikariCP 的神器配置:
只要某个连接超过一定时间没关闭,它就会打印堆栈信息,告诉你是哪一行代码泄漏的。

代码解析:一个典型的泄漏案例(错误示例)

下面的代码很多人都会这么写,但这是导致泄漏的元凶之一:

publicUsergetUser(intuserId)throwsSQLException{Connectionconn=dataSource.getConnection();// 借出连接PreparedStatementstmt=conn.prepareStatement("SELECT * FROM user WHERE id=?");stmt.setInt(1,userId);ResultSetrs=stmt.executeQuery();if(rs.next()){returnnewUser(rs.getInt("id"),rs.getString("name"));}// 问题:这里没有关闭任何资源!returnnull;}

问题:

  • conn 没有关闭
  • stmt 没有关闭
  • rs 没有关闭
  • 意味着连接池永远等不到这个连接回收

你的系统最多只需要几十次调用就会把连接全占满。

正确示例 Demo:用 try-with-resources 自动关闭资源

这是连接池官方推荐的最佳写法,绝对不会泄漏:

publicUsergetUser(intuserId){Stringsql="SELECT * FROM user WHERE id=?";try(Connectionconn=dataSource.getConnection();// 自动关闭PreparedStatementstmt=conn.prepareStatement(sql);){stmt.setInt(1,userId);try(ResultSetrs=stmt.executeQuery()){// 自动关闭if(rs.next()){returnnewUser(rs.getInt("id"),rs.getString("name"));}}}catch(SQLExceptione){thrownewRuntimeException("Query error",e);}returnnull;}

为什么安全?

  1. try(…) 自动调用 close()
  2. 不需要手写 finally
  3. 每一层资源都被正确回收
  4. 不管异常是否发生,连接都不会泄漏

这是避免泄漏的最终方案。

启用 leakDetectionThreshold:让 HikariCP 自动抓到泄漏点

在开发环境或测试环境中,你可以开启这个配置:

spring:datasource:hikari:leak-detection-threshold:2000# 超过2秒未关闭就打印堆栈

或 Java 配置:

HikariConfigconfig=newHikariConfig();config.setLeakDetectionThreshold(2000);// 2秒

运行后,如果某个连接超过 2 秒没关闭,会看到类似日志:

Connection leak detected: connection com.mysql.jdbc.JDBC4Connection@xxxx was not closed. Stack trace: at com.xxx.Repository.getUser(Repository.java:42) at com.xxx.Service.call(Service.java:25)

看到这一段你就知道泄漏在哪里了,比你人工排查有效一百倍。

最大连接数问题:为什么连接泄漏看起来像“数据库压力太大”?

很多时候我们误以为数据库崩了,其实是连接池被耗尽了。

比如:

maximumPoolSize:10

在这个配置下:

  • 10 个连接都泄漏
  • 第 11 个请求开始 → 直接阻塞或报错

这也是为什么:

  • 重启服务 → 自动释放连接 → 一切恢复正常
  • 跑一段时间 → 又挂了

如果你有大量并发接口访问数据库,一定要适当调高连接池大小:

maximumPoolSize:30minimumIdle:5

但不要盲目调太高,否则数据库本身会被拖垮。

实际场景分析:哪些地方最容易发生泄漏?

场景 1:在循环中不断创建连接

for(...){Connectionconn=dataSource.getConnection();// 未关闭...}

很快连接池耗尽。

场景 2:异常抛出时 finally 被遗漏

try{Connectionconn=ds.getConnection();...if(error)thrownewRuntimeException();}catch(Exceptione){log.error(e);}// 没有 finally,资源永远泄漏

场景 3:使用多层封装(容易忘记关闭)

例如 Service → Repository → Helper → DAO
每一层都可能忘记关闭 ResultSet 或 Statement。

场景 4:并发任务中手动开启连接,但不关闭

线程池 + 手写 JDBC 特别容易踩坑。

示例测试与结果

使用错误代码 + 启用 leakDetectionThreshold,会得到:

Connection leak detected ... at com.xxx.Repository.getUser(Repository.java:42)

使用 try-with-resources 改写,并开启 Hikari 日志:

  • 连接借出、归还都正常
  • 系统运行稳定
  • 不会再出现连接耗尽、阻塞、重启恢复等问题

这是最可靠的验证方式。

总结

数据库连接池泄漏本质上是连接借出后没有关闭,导致连接池永远无法回收资源。
要彻底解决这个问题,你需要做到:

  1. 优先使用 try-with-resources,自动关闭所有 JDBC 资源
  2. 合理配置最大连接数,避免高峰期被耗尽
  3. 开启 leakDetectionThreshold,让连接池帮你自动排查泄漏堆栈

只要这三步做到位,你的数据库连接池就能保持长期稳定,不会再出现“运行 10 分钟就卡死”这种恼人的情况。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 7:51:24

TikTok直播卡顿掉帧?直播专线带来高稳定推流

TikTok直播卡顿和掉帧的根源在于推流路径的国际链路质量不稳定、数据丢包率高以及本地网络上传抖动大。直播专线通过提供专属的、优化的国际通道,有效规避了公网拥堵和国际海缆不稳定因素,确保了推流码率的连续性和稳定性,是解决TikTok直播高…

作者头像 李华
网站建设 2026/5/10 18:13:39

数据要素方案,数据资产解决方案(文件)

数据要素是以电子形式参与生产经营、发挥重要价值的资源。在互联网普及背景下,全球数据爆发式增长,成为驱动实体经济变革、推动数字经济深入发展的核心新生产要素,具有虚拟性、非消耗性、依赖性等特征。数据资产建设需遵循“数据资源化 - 数据…

作者头像 李华
网站建设 2026/5/10 18:13:35

AntiSplit-M:终极APK合并工具,一键解决拆分安装难题

AntiSplit-M:终极APK合并工具,一键解决拆分安装难题 【免费下载链接】AntiSplit-M App to AntiSplit (merge) split APKs (APKS/XAPK/APKM) to regular .APK file on Android 项目地址: https://gitcode.com/gh_mirrors/an/AntiSplit-M 在当今And…

作者头像 李华
网站建设 2026/5/11 23:57:16

LeetCode 83/237/82 链表删除问题-盒子模型

目录 一、LeetCode 83 移除排序链表中的重复元素(保留一个) 题目核心 核心难点拆解 深度思路(盒子 - 标签 - 纸条模型) 代码实现 易踩坑点 & 底层原理 二、LeetCode 237 删除链表中的节点(无法访问头节点&am…

作者头像 李华
网站建设 2026/5/15 4:19:47

33、网络服务与邮件服务全解析

网络服务与邮件服务全解析 1. DHCP 服务器配置与管理 在配置 DHCP 服务器时,若服务提示配置文件中缺少 “}”,需先定位问题所在行并补充 “}”,之后重启 DHCP 服务: # service dhcpd start启动成功后,可通过以下命令验证服务是否运行: # service dhcpd status在客户…

作者头像 李华