You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate内部连接池疑似泄漏?关闭会话仍触发最大连接数异常

解决Hibernate连接池耗尽的问题

这个问题我碰到过好多次,核心原因有两个:未正确处理异常导致的连接泄漏,以及缺失必要的连接池配置,咱们一步步来解决:

1. 代码层面:异常场景下Session未关闭,导致连接泄漏

你当前的代码里,如果query.list()或者tx.commit()抛出异常,session.close()就不会执行——这意味着这个连接会一直被占用,不会回到连接池里。时间长了,所有连接都被泄漏的Session占着,自然就会报“连接池已达最大容量”的错误。

修正方案:用try-with-resources或try-finally确保Session必关闭

因为Hibernate的Session实现了AutoCloseable接口,用try-with-resources是最简洁的方式,它会自动帮你关闭Session,不管有没有异常:

@Override
public Book find(String bookLink) {
    try (Session session = sessionFactory.openSession()) {
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Book where link = :link");
        query.setParameter("link", bookLink);
        List<Book> list = query.list();
        tx.commit();
        return list.isEmpty() ? new Book() : list.get(0);
    } catch (Exception e) {
        // 捕获异常时记得回滚未提交的事务
        Transaction tx = session.getTransaction();
        if (tx != null && tx.isActive()) {
            tx.rollback();
        }
        // 可以添加日志记录,再把异常抛出去或者根据业务处理
        throw new RuntimeException("查询书籍失败", e);
    }
}

如果你的Java版本低于8,就用传统的try-finally写法:

@Override
public Book find(String bookLink) {
    Session session = null;
    Transaction tx = null;
    try {
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        Query query = session.createQuery("from Book where link = :link");
        query.setParameter("link", bookLink);
        List<Book> list = query.list();
        tx.commit();
        return list.isEmpty() ? new Book() : list.get(0);
    } catch (Exception e) {
        if (tx != null && tx.isActive()) {
            tx.rollback();
        }
        throw new RuntimeException("查询书籍失败", e);
    } finally {
        // 确保Session一定会被关闭
        if (session != null && session.isOpen()) {
            session.close();
        }
    }
}

2. 配置层面:缺失连接池参数,默认容量过小

你的hibernate.cfg.xml里没有配置连接池相关参数,Hibernate默认的DriverManagerConnectionProviderImpl是一个非常简单的连接池,默认最大连接数只有10左右。而你的代码里用到了ThreadPoolExecutor多线程执行,并发请求一多,很容易就把连接池耗光。

修正方案:添加连接池配置,或更换专业连接池

方案一:给默认连接池加参数

在hibernate.cfg.xml的<session-factory>里添加以下配置:

<!-- 设置连接池最大容量,根据你的并发量调整,比如20 -->
<property name="hibernate.connection.pool_size">20</property>
<!-- 设置连接超时时间,自动回收闲置过久的连接(防止泄漏的连接一直占坑) -->
<property name="hibernate.connection.timeout">30000</property>

方案二:更换为更可靠的连接池(推荐)

默认的连接池功能太弱,建议换成HikariCP(目前性能最好的连接池)或者C3P0。以HikariCP为例:

  1. 先添加HikariCP的依赖(Maven为例):
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-hikaricp</artifactId>
    <version>你的Hibernate版本</version>
</dependency>
  1. 修改hibernate.cfg.xml的连接池配置:
<!-- 指定用HikariCP作为连接池 -->
<property name="hibernate.connection.provider_class">com.zaxxer.hikari.hibernate.HikariConnectionProvider</property>
<!-- 最大连接数 -->
<property name="hibernate.hikari.maximumPoolSize">20</property>
<!-- 最小空闲连接数 -->
<property name="hibernate.hikari.minimumIdle">5</property>
<!-- 连接闲置超时时间(毫秒),超时自动回收 -->
<property name="hibernate.hikari.idleTimeout">30000</property>
<!-- 连接最长生命周期 -->
<property name="hibernate.hikari.maxLifetime">1800000</property>

总结

先修复代码里的Session关闭逻辑,确保异常场景下连接也能释放;再根据你的并发量配置合适的连接池参数,或者更换专业的连接池。这样就能彻底解决连接池耗尽的问题了。

内容的提问来源于stack exchange,提问作者Buddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:02:03