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

Spring Boot+HikariPool无法获取JDBC Connection问题求助

解决Spring Boot+Hikari连接池无法获取JDBC连接的问题

问题根源分析

你的代码和配置存在几个核心问题,直接导致连接池耗尽:

  • 无限制创建线程:在while循环中每次都new Thread(),循环次数超500次时会生成大量线程,每个线程都要抢占数据库连接,直接打满连接池。
  • 连接持有时间过长:API调用属于高耗时操作,却和数据库save操作放在同一线程的事务流程中,导致连接被长时间占用无法释放。
  • 事务范围不合理:@Transactional加在类上时,会让包含耗时API调用的整个方法都处于事务中,进一步延长连接持有周期。
  • 数据库端连接限制:PostgreSQL默认有max_connections配置,若Hikari的maximum-pool-size超过该值,即使调大池大小也无济于事。

具体解决方案

1. 用线程池替代手动创建线程

不要直接new Thread(),通过线程池控制并发数,避免瞬间创建大量线程耗尽连接:

// 定义线程池(可使用Spring的ThreadPoolTaskExecutor,或手动创建)
private ExecutorService executor = Executors.newFixedThreadPool(10); // 根据业务场景调整核心线程数

int count = programRepository.countBlackoutPending();
while (count > 0) {
    // ...
    executor.submit(() -> {
        // 业务逻辑
    });
    // 每次循环后重新获取count,避免无限循环
    count = programRepository.countBlackoutPending();
}

2. 分离耗时操作与数据库操作,缩短连接持有时间

把API调用这类非数据库操作移出连接/事务的持有周期,先查询数据、释放连接,再处理API,最后批量更新:

// 1. 查询数据(获取连接→查询完成后立即释放)
List<ProgramEntity> programList = programRepository.findAllByID();

// 2. 执行API调用(此时不占用数据库连接)
programList.forEach(program -> {
    // API调用逻辑
});

// 3. 批量保存更新(一次性获取连接,批量操作后释放)
programRepository.saveAll(programList);

3. 优化事务注解的使用

不要将@Transactional加在包含耗时API调用的方法上,仅在纯数据库操作的方法上添加:

// 仅在数据库操作方法上加事务
@Transactional
public void savePrograms(List<ProgramEntity> programs) {
    programRepository.saveAll(programs);
}

// 业务方法中调用,API调用不在事务范围内
public void processPrograms() {
    List<ProgramEntity> list = programRepository.findAllByID();
    // API调用逻辑
    savePrograms(list);
}

4. 检查并调整连接池与数据库配置

  • 检查PostgreSQL连接限制:执行SQL命令show max_connections;查看数据库允许的最大连接数,Hikari的maximum-pool-size必须小于等于该值(建议预留10-20个连接给数据库管理员及其他系统)。
  • 开启Hikari连接泄漏检测:在application.properties中添加配置,排查连接未释放的情况:
spring.datasource.hikari.leak-detection-threshold=60000 # 60秒检测连接泄漏
  • 优化连接池其他参数:合理设置闲置超时、最小空闲连接数,避免连接闲置过久或数量不足:
spring.datasource.hikari.minimum-idle=20
spring.datasource.hikari.idle-timeout=300000

5. 修复循环逻辑bug

确保while循环中每次都会重新获取count值,否则会陷入无限循环,不断创建线程耗尽资源:

int count = programRepository.countBlackoutPending();
while (count > 0) {
    // 处理逻辑
    // 必须重新查询count,否则循环无法终止
    count = programRepository.countBlackoutPending();
}

内容的提问来源于stack exchange,提问作者M.A.Murali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:33:29