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

SpringBoot应用测试时未释放数据库连接导致PostgreSQL连接数超限问题咨询

解决多个Spring测试注解导致PostgreSQL连接耗尽的问题

我碰到过好几次这种情况,尤其是项目里混合使用@JDBCTest和@SpringBootTest的时候,特别容易踩连接数过多的坑。咱们一步步拆解问题和解决办法:

为什么连接没释放/上下文没终止?

1. 测试上下文重复创建,连接池无法回收

Spring Test默认会复用测试上下文,但如果你的测试类之间配置不一致(比如有的用@JDBCTest,有的用@SpringBootTest,或者注解里的属性、导入的配置不同),Spring会为每个不同的配置创建全新的ApplicationContext。每个上下文都会初始化自己的连接池,而如果这些上下文没有被正确销毁,连接池里的连接就会一直占用PostgreSQL的客户端连接数,直到耗尽。

2. @JDBCTest的切片特性可能导致连接回收不彻底

@JDBCTest是Spring的切片测试注解,它只会初始化JDBC相关的Bean(比如JdbcTemplate、数据源),不会启动完整的Spring Boot应用。但如果你的测试代码里有自定义Bean或者未被Spring托管的资源,可能会导致连接没有被正确归还给连接池。

3. 连接池配置不合理

如果你的连接池(比如Spring Boot默认的HikariCP)配置的maximumPoolSize太大,或者测试时每个上下文都创建一个连接池,很快就会超过PostgreSQL默认的max_connections(默认是100)。另外,如果连接池的autoCommit、connectionTimeout等参数配置不当,也可能导致连接无法被及时回收。

具体解决办法

1. 统一测试上下文,减少重复创建

  • 如果测试都是JDBC相关的,尽量统一用@JDBCTest,避免混用@SpringBootTest。如果必须用@SpringBootTest,确保多个测试类的配置一致(比如相同的@TestPropertySource、@Import等),让Spring复用同一个上下文。
  • 对于必须使用不同上下文的测试,添加@DirtiesContext注解,强制Spring在测试结束后销毁上下文:
    • 用@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD):每个测试方法执行完销毁上下文
    • 用@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS):整个测试类执行完销毁上下文
      不过这个注解要谨慎使用,因为销毁上下文会增加测试耗时。

2. 确保连接被正确归还给连接池

  • 检查测试代码,所有手动获取的数据库连接都要用try-with-resources自动关闭:
try (Connection conn = dataSource.getConnection()) {
    // 执行数据库操作
} catch (SQLException e) {
    // 处理异常
}
  • 优先使用JdbcTemplate,它会自动管理连接的获取和归还,避免手动操作连接的疏漏。

3. 优化测试环境的连接池配置

在application-test.properties里调整连接池参数:

# HikariCP配置
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.max-lifetime=1800000
  • 把maximum-pool-size设小,避免单个上下文占用过多连接
  • 设置合理的idle-timeout和max-lifetime,让连接池自动回收闲置和过期的连接

4. 手动强制关闭上下文(极端情况)

如果上面的方法都无效,可以在测试类里添加@AfterAll方法,手动销毁ApplicationContext:

@SpringBootTest
public class MyDbTest {
    @Autowired
    private ConfigurableApplicationContext context;

    @AfterAll
    void tearDown() {
        context.close();
    }
}

这样能确保每个测试类执行完后都会销毁上下文,释放连接池资源。

额外排查技巧

  • 测试运行时,用PostgreSQL命令查看当前连接数,确认连接是否持续增长:
SELECT count(*) FROM pg_stat_activity;
  • 开启Spring测试日志(设置logging.level.org.springframework.test.context=DEBUG),查看上下文的创建和销毁日志,确认是否有上下文未被销毁的情况。

内容的提问来源于stack exchange,提问作者mayTree

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 11:28:15