news 2026/6/10 22:20:24

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

作者头像

张小明

前端开发工程师

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/6/10 3:01:49

CAMEL多智能体框架:构建高效智能协作系统的完整指南

CAMEL多智能体框架:构建高效智能协作系统的完整指南 【免费下载链接】camel 🐫 CAMEL: Communicative Agents for “Mind” Exploration of Large Language Model Society (NeruIPS2023) https://www.camel-ai.org 项目地址: https://gitcode.com/GitH…

作者头像 李华
网站建设 2026/6/10 12:26:13

java计算机毕业设计热点推荐个性化新闻系统 基于SpringBoot的千人千面资讯推荐平台 JavaWeb热点新闻聚合与个性化推送系统

计算机毕业设计热点推荐个性化新闻系统slo749(配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。信息爆炸时代,千篇一律的门户首页早已让用户审美疲劳,只有“…

作者头像 李华
网站建设 2026/6/10 12:24:07

2025年中考英语高频必备300词

包含:核心动词、易错名词、高频形容词/副词、关键虚词及场景词汇。 重点标注:音标、词义、固定搭配及考点例句。一、核心动词 (Verbs) - 句子的引擎单词音标中文高频短语 / 考点用法accept/əksept/接受accept an invitation (接受邀请); 辨析: receive(…

作者头像 李华
网站建设 2026/6/10 12:24:18

AD9571ACPZLVD:6路参考时钟输出与集成环路滤波器, 现货库存

型号介绍:今天我要向大家介绍的是 Analog Devices 的一款滤波器——AD9571ACPZLVD。 它的核心是一个高度集成的锁相环(PLL)系统,就像一个内置的、经验丰富的指挥家,能从外部的25MHz晶振或参考时钟(REFCLK引…

作者头像 李华
网站建设 2026/6/10 0:52:47

Redis+Caffeine 太强了!

背景在高性能的服务架构设计中,缓存是一个不可或缺的环节。在实际的项目中,我们通常会将一些热点数据存储到Redis或Memcached 这类缓存中间件中,只有当缓存的访问没有命中时再查询数据库。在提升访问速度的同时,也能降低数据库的压…

作者头像 李华