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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 22:07:08