Spring-JPA出现连接泄漏异常的原因排查求助
Spring-JPA连接泄漏问题分析(HikariCP「Apparent connection leak detected」异常)
问题场景
在Spring-JPA项目中触发了HikariCP的「Apparent connection leak detected」异常,相关堆栈信息如下:
java.lang.Exception: Apparent connection leak detected at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128) ~[HikariCP-5.0.1.jar:na] at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:46) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:113) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:143) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.connection(StatementPreparerImpl.java:54) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:153) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:183) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:155) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.sql.exec.spi.JdbcSelectExecutor.lambda$list$0(JdbcSelectExecutor.java:85) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
接口代码:
@GetMapping public ResponseEntity<?> getImComponentsList() { List<ComponentMaterial> all; try { componentAddmaterialRepository.findAllProjectedBy(); //<-- SQL < 1 sec Thread.sleep(10_000); // some heavy load... } catch (Exception ex) { logger.error(ex); throw ex; } }
Repository代码:
@RepositoryRestResource(exported = false) public interface ComponentAddmaterialRepository extends JpaRepository<ComponentAddmaterial, Integer> { List<MaterialNrDto> findAllProjectedBy(); interface MaterialNrDto { String getMaterialnr(); } }
使用投影后仍出现相同错误,场景为小型JPA查询后执行耗时操作。
问题原因
核心原因是数据库连接的生命周期没有被正确控制:
- Spring MVC控制器方法默认不会自动管理事务边界,调用Repository查询方法时,Hibernate会从HikariCP获取数据库连接,该连接会绑定到当前隐式事务上下文(Spring会为Repository方法自动创建隐式事务)。
- 这个隐式事务会持续到整个控制器方法执行完毕,也就是说查询完成后,连接并没有立即归还连接池,而是被一直持有,直到
Thread.sleep(10_000)执行完毕、方法结束。 - 当连接被持有时间超过HikariCP的
leakDetectionThreshold配置值时,就会触发「Apparent connection leak detected」异常。 - 投影仅改变查询结果的返回结构,不会影响事务和连接的生命周期,因此换用投影无法解决问题。
解决方案
1. 显式控制事务边界(推荐)
将查询操作封装到单独的Service方法中,并添加@Transactional(readOnly = true)注解,确保查询完成后事务立即提交,连接归还到连接池:
Service层代码:
@Service public class ComponentMaterialService { private final ComponentAddmaterialRepository repository; public ComponentMaterialService(ComponentAddmaterialRepository repository) { this.repository = repository; } @Transactional(readOnly = true) public List<MaterialNrDto> getMaterialNumbers() { return repository.findAllProjectedBy(); } }
修改后的控制器代码:
@GetMapping public ResponseEntity<?> getImComponentsList() { try { // 查询操作在事务内执行,方法结束后连接立即归还 List<MaterialNrDto> materialNumbers = componentMaterialService.getMaterialNumbers(); Thread.sleep(10_000); // 耗时操作不再占用数据库连接 return ResponseEntity.ok(materialNumbers); } catch (Exception ex) { logger.error(ex); throw ex; } }
@Transactional(readOnly = true)会让Spring在方法执行完毕后自动提交事务,Hibernate随即释放连接到HikariCP,后续的耗时操作不会再占用连接。
2. 调整HikariCP泄漏检测阈值(治标不推荐)
如果临时需要缓解问题,可以调整HikariCP的leakDetectionThreshold配置,延长检测时间,但这只是掩盖问题,无法从根本上解决连接被长期占用的问题:
spring.datasource.hikari.leak-detection-threshold=20000 # 设置为20秒
内容的提问来源于stack exchange,提问作者Raw
相关产品推荐
相关产品推荐

