You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot微服务JdbcTemplate数据库连接异常:连接已关闭

解决Spring Boot微服务长时间运行后无法连接SQL Server的问题

你遇到的是典型的连接池失效连接未被及时清理的问题——SQL Server会主动断开长时间闲置的连接,但你的连接池还误以为这些连接可用,当服务尝试使用已关闭的连接时就会抛出The connection is closed错误。重启服务会重建连接池,所以暂时恢复,但闲置一段时间后问题必然复发。

结合你使用多数据源的场景,下面给出具体的排查和修复方案:

一、核心原因拆解

SQL Server默认会在连接闲置30分钟后自动断开(通过remote query timeoutconnection timeout配置),如果你的连接池没有配置连接有效性检测机制,就会导致连接池里堆积大量失效连接,最终服务获取到死连接时触发报错。

二、针对多数据源的修复步骤

1. 配置连接池的有效性检测参数

不管你用的是Spring Boot默认的HikariCP,还是Druid这类第三方连接池,都必须开启连接有效性检测,确保连接池定期清理失效连接,且在获取连接时验证可用性。

如果你用HikariCP(Spring Boot默认)

在每个数据源的配置中添加以下参数:

# 第一个数据源配置
spring.datasource.first.hikari.max-lifetime=1800000  # 连接最大生命周期(30分钟,小于SQL Server闲置超时)
spring.datasource.first.hikari.connection-test-query=SELECT 1
spring.datasource.first.hikari.validation-timeout=3000
spring.datasource.first.hikari.leak-detection-threshold=2000

# 第二个数据源配置
spring.datasource.second.hikari.max-lifetime=1800000
spring.datasource.second.hikari.connection-test-query=SELECT 1
spring.datasource.second.hikari.validation-timeout=3000
spring.datasource.second.hikari.leak-detection-threshold=2000
  • max-lifetime:设置为比SQL Server闲置超时短的值,确保连接池在数据库断开前主动回收连接
  • connection-test-query:获取连接时执行的验证SQL,SQL Server用SELECT 1即可
  • validation-timeout:连接验证的超时时间
  • leak-detection-threshold:检测连接泄漏的阈值,能帮你排查是否有连接未被正确释放

如果你用Druid连接池

在每个数据源配置中添加:

# 第一个数据源
spring.datasource.first.druid.test-on-borrow=true
spring.datasource.first.druid.test-while-idle=true
spring.datasource.first.druid.validation-query=SELECT 1
spring.datasource.first.druid.time-between-eviction-runs-millis=60000
spring.datasource.first.druid.min-evictable-idle-time-millis=1800000

# 第二个数据源同理复制上述配置
  • test-on-borrow:获取连接时立即验证有效性
  • test-while-idle:空闲时定期检查连接状态
  • validation-query:验证连接可用的SQL语句
  • time-between-eviction-runs-millis:定期清理失效连接的间隔
  • min-evictable-idle-time-millis:连接闲置多久后被自动回收

2. 检查数据库端的连接超时配置

登录SQL Server,执行以下SQL检查全局连接配置:

-- 查看远程查询超时时间
EXEC sp_configure 'remote query timeout';
-- 查看连接超时时间
SELECT name, value FROM sys.configurations WHERE name = 'connection timeout';

如果remote query timeout设置过短(比如小于20分钟),可以适当调整,但更推荐在连接池端通过max-lifetime适配,避免修改数据库全局配置影响其他应用。

3. 排查代码中的连接泄漏问题

如果配置有效性检测后问题依然存在,大概率是代码中存在连接泄漏——即获取了数据库连接但未正确关闭(比如try-with-resources使用不当,或事务异常导致连接未释放)。

排查方法:

  • 开启连接池的泄漏检测(比如HikariCP的leak-detection-threshold),日志会打印泄漏连接的调用栈,定位问题代码
  • 检查所有数据库操作是否用try-with-resources包裹,确保连接自动关闭:
try (Connection conn = dataSource.getConnection()) {
    // 执行数据库操作逻辑
} catch (SQLException e) {
    // 异常处理
}
  • 检查Spring事务配置是否正确,确保事务完成后连接被正常释放回连接池

4. 多数据源配置类的注意事项

如果你的自定义数据源配置类是手动创建连接池实例,一定要确保每个数据源都配置了上述有效性参数。比如用HikariCP手动创建数据源的代码:

@Bean
@Primary
public DataSource firstDataSource() {
    HikariDataSource dataSource = new HikariDataSource();
    dataSource.setJdbcUrl("jdbc:sqlserver://localhost:1433;databaseName=db1");
    dataSource.setUsername("user");
    dataSource.setPassword("pass");
    // 务必添加连接有效性配置
    dataSource.setMaxLifetime(1800000);
    dataSource.setConnectionTestQuery("SELECT 1");
    dataSource.setValidationTimeout(3000);
    dataSource.setLeakDetectionThreshold(2000);
    return dataSource;
}

两个数据源的配置要保持一致,不要遗漏任何一个。

三、验证修复效果

配置完成后部署服务,观察以下几点:

  • 查看连接池的监控日志(比如HikariCP会打印连接池状态)
  • 让服务运行超过之前出现问题的时长,检查是否还会触发连接关闭错误
  • 模拟长时间闲置后发起请求,验证连接池是否能正确获取有效连接

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

火山引擎 最新活动