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

Tomcat服务器任务执行期间JDBC连接丢失问题求助

我之前在类似的Spring Boot + Tomcat环境里碰到过一模一样的JDBC连接丢失问题,结合你的架构和调用链路,给你梳理下排查方向和解决办法:

先明确下你的系统架构背景

  • 认证服务:基于Keycloak
  • 应用服务器:单台Tomcat 8
  • 核心公共服务:应用A(部署在Tomcat 8上,Spring Boot + Java 8开发)
  • 客户端应用:应用B等其他Web应用(均为Spring Boot + Java 8开发)
  • 数据库层:
    • MySQL(读写分离,使用独立Schema)
    • 只读SQL Server

你的问题场景:应用B调用应用A的API,应用A连接只读SQL Server读取记录时,Tomcat任务执行期间出现JDBC连接丢失。


一、先从SQL Server端排查根源

  1. 检查数据库连接超时配置
    很多时候是SQL Server主动踢掉了超时连接,先查这两个关键配置:

    • 执行以下SQL查看远程查询超时时间(默认600秒/10分钟):
      SELECT name, value_in_use FROM sys.configurations WHERE name = 'remote query timeout (s)'
      
      如果你的API查询耗时超过这个值,数据库会强制断开连接。
    • 查看SQL Server的连接超时设置(默认30分钟),确保连接池的存活时间小于这个值,避免持有无效连接。
  2. 查看SQL Server错误日志
    直接找数据库日志里的连接断开相关错误,比如:

    • Error: 10054, Severity: 20, State: 0:TCP连接被重置(通常是网络或防火墙问题)
    • Error: 1205, Severity: 13, State: 51:死锁导致连接断开
      这些日志能直接帮你定位到数据库端的问题。

二、排查应用A的Spring Boot连接池配置

Spring Boot默认用HikariCP连接池,这是最容易出问题的环节:

  1. 调整连接池超时与存活配置

    • 确保spring.datasource.hikari.max-lifetime设置小于SQL Server的连接超时(比如SQL Server默认30分钟,就把max-lifetime设为1740000毫秒/29分钟),避免连接池持有已被数据库踢掉的无效连接。
    • 开启连接有效性验证,每次获取连接时都检查是否可用:
      spring.datasource.hikari.test-on-borrow=true
      spring.datasource.hikari.validation-query=SELECT 1
      spring.datasource.hikari.validation-timeout=5000
      
    • 如果API执行耗时较长,调大spring.datasource.hikari.connection-timeout,避免连接池在获取连接时超时。
  2. 检测连接泄漏

    • 启用HikariCP的泄漏检测:spring.datasource.hikari.leak-detection-threshold=2000(单位毫秒),如果代码里有未正确释放的连接,日志会打印泄漏的栈信息。
    • 检查代码是否用了try-with-resources语法确保资源释放:
      try (Connection conn = dataSource.getConnection();
           Statement stmt = conn.createStatement();
           ResultSet rs = stmt.executeQuery(sql)) {
          // 处理查询结果
      } catch (SQLException e) {
          // 异常处理逻辑
      }
      

    这种语法能自动关闭Connection、Statement、ResultSet,避免连接泄漏。

三、排查Tomcat 8的线程与连接配置

  1. Tomcat线程池配置
    检查server.xml里的线程池和Connector配置,确保线程数足够,不会因为线程耗尽导致任务阻塞:

    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
              maxThreads="200" minSpareThreads="20" maxIdleTime="60000"/>
    <Connector port="8080" protocol="HTTP/1.1"
               executor="tomcatThreadPool"
               connectionTimeout="20000"
               redirectPort="8443"/>
    

    注意这里的connectionTimeout是Tomcat处理HTTP请求的超时,不是JDBC连接超时,但如果应用B的请求超时,也可能引发后续JDBC连接异常。

  2. 如果用了Tomcat自带的JDBC连接池
    若应用A没使用HikariCP而是Tomcat JDBC池,启用废弃连接回收和日志:

    <Resource name="jdbc/SQLServerDB" auth="Container"
              type="javax.sql.DataSource" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
              url="jdbc:sqlserver://localhost:1433;databaseName=YourReadOnlyDB"
              username="readonlyUser" password="yourPass"
              maxTotal="100" maxIdle="20" minIdle="5"
              removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true"/>
    

四、排查网络层面问题

  1. 检查防火墙/中间件超时
    如果应用A和SQL Server之间有防火墙、负载均衡或者代理,这些设备通常会主动断开长时间空闲或超时的连接(比如很多防火墙默认5分钟超时)。检查这些设备的连接超时设置,确保大于你的API最大执行时间。

  2. 测试网络稳定性
    用ping(Windows/Linux)或mtr(Linux)测试应用A服务器到SQL Server的连通性,看是否有丢包、延迟过高的情况,网络不稳定也会导致连接随机断开。

五、代码与查询优化

  1. 优化SQL查询性能
    慢查询是连接超时的常见原因,用SQL Server的执行计划分析你的查询语句,看是否有全表扫描、缺少索引的情况,添加合适的索引能大幅缩短查询时间,避免超时。

  2. 异步处理(可选)
    如果API确实需要长时间执行,可以用Spring的@Async注解把查询逻辑改成异步,避免长时间占用JDBC连接和Tomcat线程:

    @Service
    public class SqlServerService {
        @Async
        public CompletableFuture<YourRecord> fetchRecordAsync(String id) {
            // 执行SQL查询逻辑
            return CompletableFuture.completedFuture(record);
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:53:14