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" />
确保验证查询有效性
确认validationQuery配置的SQL能在MySQL中正常执行,避免使用带分号或无效的语句,保证testOnBorrow和testWhileIdle能准确检测连接状态。排查并修复连接泄漏
利用logAbandoned=true生成的日志,定位长时间占用连接的代码逻辑,检查是否存在未在finally块中释放ResultSet、Statement或Connection的情况(Spring JdbcTemplate通常自动管理,但自定义JDBC操作需注意),及时修复泄漏问题。
内容的提问来源于stack exchange,提问作者user6742120
相关产品推荐
相关产品推荐

