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为例:
- 先添加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>
- 修改
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
相关产品推荐
相关产品推荐

