Spring Boot 1.5.6+HikariCP2.7.3+Hibernate连接泄漏问题求助
首先明确你的环境配置:
- Spring Boot Version: 1.5.6
- Hikari Pool Version: 2.7.3
- ORM框架: Hibernate
你遇到的是HikariCP检测到的连接泄漏问题,完整报错堆栈如下:
java.lang.Exception: Apparent connection leak detected at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:386) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:87) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:112) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:230) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:237) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:214) at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52) at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1512) at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:45) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:189) at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380) at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:447) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) at ariba.sellerdirect.fileprocessor.processor.SingleItemProcessor$$EnhancerBySpringCGLIB$$a84b87d5.diffAndStoreMasterItem() at ariba.sellerdirect.fileprocessor.processor.csv.MasterContentCSVProcessor.processDiffAndStoreItem(MasterContentCSVProcessor.java:66) at ariba.sellerdirect.fileprocessor.processor.csv.MasterContentCSVProcessor.processSingleItem(MasterContentCSVProcessor.java:43) at ariba.sellerdirect.fileprocessor.processor.csv.GeneralCSVProcessor.processFile(GeneralCSVProcessor.java:109) at ariba.sellerdirect.fileprocessor.processor.csv.GeneralCSVProcessor$$FastClassBySpringCGLIB$$6777a9.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at ariba.sellerdirect.util.PerformanceMonitorInterceptor.invokeUnderTrace(PerformanceMonitorInterceptor.java:24) at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke(AbstractTraceInterceptor.java:129) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
从堆栈能看出,泄漏发生在事务启动流程中,HikariCP检测到连接未被正确归还到池中。下面是针对性的排查和解决步骤:
1. 修正Hibernate连接释放模式
在Spring Boot 1.5.x版本中,Spring管理事务时,Hibernate默认的连接释放模式可能不是最优配置。你需要在application.properties或application.yml中添加以下配置,确保事务结束后Hibernate自动将连接归还到HikariCP:
spring.jpa.properties.hibernate.connection.release_mode=after_transaction
2. 检查手动资源管理代码
堆栈显示业务代码的触发点是SingleItemProcessor.diffAndStoreMasterItem(),如果你的代码中存在手动获取Session或Connection但未关闭的情况,必然会导致连接泄漏。比如:
- 手动调用
sessionFactory.openSession()但未在finally块中关闭 - 直接从数据源获取
Connection后未调用close()
请检查MasterContentCSVProcessor和SingleItemProcessor中的代码,确保所有手动获取的资源都在finally块中释放,示例代码如下:
Session session = null; try { session = sessionFactory.openSession(); // 业务逻辑操作 } finally { if (session != null && session.isOpen()) { session.close(); } }
3. 优化HikariCP泄漏检测配置
HikariCP默认的泄漏检测阈值是10秒,你可以调整这个值(比如设置为20秒)并开启日志,以便更精准地定位泄漏的代码位置。添加以下配置:
spring.datasource.hikari.leakDetectionThreshold=20000 spring.datasource.hikari.log-leak-detection=true
当连接超过20秒未归还时,HikariCP会打印更详细的泄漏追踪日志,帮助你定位问题代码。
4. 检查事务传播行为
如果事务方法中存在嵌套调用,或者@Transactional的传播属性配置不当(比如滥用REQUIRES_NEW),也可能导致连接未被正确释放。请检查所有事务注解的传播属性,确保符合业务逻辑,避免不必要的事务嵌套。
5. 升级依赖版本(推荐)
Spring Boot 1.5.6和HikariCP 2.7.3都是较旧的版本,存在一些已知的连接管理bug。建议你升级到Spring Boot 1.5.x的最新稳定版(比如1.5.22.RELEASE),对应的HikariCP版本也会同步升级,很多旧的连接泄漏问题都已被修复。
先从配置和代码检查入手,一般就能解决问题。如果仍未解决,升级依赖应该能修复大部分历史bug。
内容的提问来源于stack exchange,提问作者Praveen

