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

Tomcat 8下Tomcat JDBC连接池出现连接已关闭异常求助

问题:Tomcat JDBC连接池运行一段时间后抛出Connection已关闭异常

我们的应用部署在Tomcat 8上,启动运行15-20分钟后抛出以下异常:

SQL state [null]; error code [0]; Connection has already been closed.; nested exception is java.sql.SQLException: Connection has already been closed

异常堆栈信息:

at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1542)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:667)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:738)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:794)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:209)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForList(NamedParameterJdbcTemplate.java:303)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForList(NamedParameterJdbcTemplate.java:310)

当前使用的Tomcat JDBC连接池配置:

<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
    destroy-method="close">      
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="url" value="${database.url}" />
    <property name="username" value="${database.username}" />
    <property name="password" value="${database.password}" />        
    <property name="initialSize" value="10" />
    <property name="maxActive" value="200" />
    <property name="minIdle" value="10" />
    <property name="maxIdle" value="50" />
    <property name="maxWait" value="50000" />
    <property name="fairQueue" value="true" />
    <property name="logAbandoned" value="true" />
    <property name="removeAbandoned" value="true" />    
    <property name="testOnBorrow" value="true" />
    <property name="timeBetweenEvictionRunsMillis" value="60000" />
    <property name="validationQuery" value="${database.validationQuery}" />
</bean>

---

## 可能的原因
- **数据库端主动回收空闲连接**:MySQL的`wait_timeout`或`interactive_timeout`参数设置过短(比如10-15分钟),连接池中长时间空闲的连接被数据库关闭,但连接池未检测到,仍将失效连接分配给应用。
- **连接池空闲连接检测机制不完善**:当前配置未启用`testWhileIdle`,也未设置`minEvictableIdleTimeMillis`,无法主动清理被数据库关闭的空闲连接。
- **验证查询无效**:`${database.validationQuery}`配置的SQL语句无法有效检测连接状态(比如格式错误、执行失败),导致`testOnBorrow`无法过滤失效连接。
- **连接泄漏未及时清理**:`removeAbandoned=true`但未设置`removeAbandonedTimeout`,默认超时300秒(5分钟),若应用存在长时间占用连接的操作,连接被标记为废弃关闭后,应用仍尝试使用该连接。

## 解决办法
1. **调整数据库连接超时参数**
   登录MySQL执行`SHOW VARIABLES LIKE '%timeout%';`,查看`wait_timeout`和`interactive_timeout`的值,确保其大于连接池的空闲检测超时时间。若数据库超时设置较短,可适当调大(比如设为3600秒),或后续调整连接池参数适配该值。

2. **完善连接池配置**
   在现有`dataSource`配置中添加以下关键参数:
   ```xml
   <!-- 启用空闲连接有效性检测 -->
   <property name="testWhileIdle" value="true" />
   <!-- 连接空闲9分钟后被驱逐(需小于数据库wait_timeout) -->
   <property name="minEvictableIdleTimeMillis" value="540000" />
   <!-- 设置废弃连接超时时间为3分钟,根据业务调整 -->
   <property name="removeAbandonedTimeout" value="180" />
   <!-- 明确MySQL有效验证查询语句 -->
   <property name="validationQuery" value="SELECT 1" />
   <!-- 验证查询超时时间5秒 -->
   <property name="validationQueryTimeout" value="5" />
  1. 确保验证查询有效性
    确认validationQuery配置的SQL能在MySQL中正常执行,避免使用带分号或无效的语句,保证testOnBorrow和testWhileIdle能准确检测连接状态。

  2. 排查并修复连接泄漏
    利用logAbandoned=true生成的日志,定位长时间占用连接的代码逻辑,检查是否存在未在finally块中释放ResultSet、Statement或Connection的情况(Spring JdbcTemplate通常自动管理,但自定义JDBC操作需注意),及时修复泄漏问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:36:38