tomcat dbcp 基于jndi配置时出现java.sql.SQLException: Already closed

本文讨论了在Web应用中遇到的数据库连接超时问题,并提供了MySQL和Oracle数据库解决该问题的方法,包括在Context.xml中配置验证查询,以确保连接的有效性和避免连接关闭导致的问题。


最近观察生产环境发现一个现象,一段时间不操作,再重新操作时,数据库连接第一次会出现:java.sql.SQLException: Already closed.,如下:




error log: (org.springframework.dao.RecoverableDataAccessException: PreparedStatementCallback; SQL [select user_id,login_name from t_sys_user where login_name=? and password=?]; The last packet successfully received from the server was1290665 seconds ago.The last packet sent successfully to the server was 1290665 seconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was1290665 seconds ago.The last packet sent successfully to the server was 1290665 seconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem. )


数据源是用tomcat dbcp 基于jndi配置管理的,查了下,如下:


原因:

You're probably running into the fact that MYSQL closes connections which have been open "too long".
Probably if you make the request to the server again, you'll find thatit works because the connection is reopened.


解决方法:

One way to deal with this is to add the following to yourcontext.xmlResource:

validationQuery="select 1" (基于mysql)

validationQuery="select 1 from dual" (基于oracle)


代价:

This causes a very cheap test query to always be run first; if the connection has been closed, this gets the failure, and
then a new connection is opened.


细想下原来用weblogic jdbc jndi的配置有一个专门的配置项来配置这个test query,配置tomcat时粗心大意了 :(


### 问题分析 `org.springframework.jdbc.UncategorizedSQLException` 是 Spring JDBC 框架中的一种异常,通常表示在执行数据库操作发生了未知的 SQL 异常。根据提供的信息,错误提示 `java.sql.SQLException: connection closed` 表明在执行查询或更新操作数据库连接已被关闭[^2]。 以下是可能的原因及解决方案: --- ### 可能原因及解决方法 #### 1. 数据库连接池配置不当 如果数据库连接池(如 HikariCP、C3P0 或 DBCP配置不正确,可能导致连接被过早关闭。例如,连接池中的空闲连接超间设置过短,或者最大连接数不足。 **解决方案:** 检查数据库连接池的配置参数,确保以下参数合理: - `idleTimeout`: 空闲连接的最大存活间。 - `maxLifetime`: 连接的最大存活间。 - `connectionTestQuery`: 配置一个测试查询以验证连接的有效性。 示例配置(HikariCP): ```yaml spring: datasource: hikari: idle-timeout: 300000 # 空闲连接超间(毫秒) max-lifetime: 1800000 # 连接最大存活间(毫秒) connection-test-query: SELECT 1 # 测试连接的SQL语句 ``` --- #### 2. 数据库连接未正确释放 如果应用程序未正确释放数据库连接,可能导致连接池中的可用连接耗尽,从而引发连接关闭的问题。 **解决方案:** 确保在代码中正确释放数据库连接。Spring 中通常通过事务管理器自动管理连接,但如果手动管理连接,则需要调用 `DataSourceUtils.releaseConnection` 方法来释放连接[^2]。 示例代码: ```java import org.springframework.jdbc.datasource.DataSourceUtils; public void releaseConnection(Connection conn, DataSource dataSource) { try { DataSourceUtils.releaseConnection(conn, dataSource); } catch (Exception ex) { // 记录日志 } } ``` --- #### 3. 数据库连接被外部因素中断 网络问题、数据库服务器重启或数据库配置更改(如字符集修改)可能导致现有连接失效。 **解决方案:** - 检查数据库服务器的日志,确认是否有重启或网络中断的情况。 - 如果修改了表结构(如将 `nickname` 列的字符集更改为 `utf8mb4`),确保所有客户端和连接池配置与新字符集兼容[^4]。 示例 SQL: ```sql ALTER TABLE user MODIFY nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` --- #### 4. 事务锁超 如果查询或更新操作涉及长间锁定的记录,可能导致事务锁超,进而引发连接关闭的问题。 **解决方案:** 优化 SQL 查询,减少锁等待间。例如,避免使用全表扫描,确保索引有效。如果确实需要长间锁定记录,可以增加事务的超间。 示例配置(Spring Boot): ```yaml spring: transaction: timeout: 30 # 事务超间(秒) ``` --- #### 5. 数据库驱动版本不匹配 如果使用的数据库驱动版本与数据库服务器版本不兼容,也可能导致连接问题。 **解决方案:** 确保使用的 JDBC 驱动版本与数据库服务器版本匹配。例如,对于 MySQL 数据库,推荐使用最新版本的 `mysql-connector-java`。 Maven 依赖示例: ```xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> ``` --- ### 总结 `UncategorizedSQLException` 和 `connection closed` 错误通常是由于连接池配置不当、连接未正确释放、网络问题或事务锁超等原因引起的。建议按照上述步骤逐一排查,并根据具体情况进行调整。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值