错误效果:
[11:31:31] [ERROR] - com.alibaba.druid.util.JdbcUtils.close(JdbcUtils.java:109) - close statement error
java.sql.SQLRecoverableException: 关闭的连接at oracle.jdbc.driver.PhysicalConnection.needLine(PhysicalConnection.java:3525) ~[ojdbc8-19.3.0.0.jar!/:19.3.0.0.0]at oracle.jdbc.driver.OracleStatement.closeOrCache(OracleStatement.java:1478) ~[ojdbc8-19.3.0.0.jar!/:19.3.0.0.0]at oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:1461) ~[ojdbc8-19.3.0.0.jar!/:19.3.0.0.0]at oracle.jdbc.driver.OracleStatementWrapper.close(OracleStatementWrapper.java:122) ~[ojdbc8-19.3.0.0.jar!/:19.3.0.0.0]at com.alibaba.druid.util.JdbcUtils.close(JdbcUtils.java:98) ~[druid-1.2.8.jar!/:1.2.8]at com.alibaba.druid.pool.vendor.OracleValidConnectionChecker.isValidConnection(OracleValidConnectionChecker.java:92) ~[druid-1.2.8.jar!/:1.2.8]at com.alibaba.druid.pool.DruidAbstractDataSource.testConnectionInternal(DruidAbstractDataSource.java:1476) ~[druid-1.2.8.jar!/:1.2.8]at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1482) ~[druid-1.2.8.jar!/:1.2.8]at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1407) ~[druid-1.2.8.jar!/:1.2.8]
出现的原因:
当数据库连接池中的连接被创建而长时间不使用的情况下,该连接会自动回收并失效,但客户端并不知道,在进行数据库操作时仍然使用的是无效的数据库连接,这样,就导致客户端程序报“ java.sql.SQLException: Io 异常: Connection reset” 或“java.sql.SQLException 关闭的连接”异常。
1:先检查druid的版本,使用1.2.*以后的版本,1.1.*版本有问题,相关文章有说明
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.11</version>
</dependency>
2:优化druid配置
spring:application:name: projectdatasource:druid:db1:driver-class-name: oracle.jdbc.OracleDriverusername: abcdpassword: 123456url: jdbc:oracle:thin:@//1.2.1.1:1521/oradsvalidation-query: SELECT 1 FROM DUALinitial-size: 30min-idle: 30max-active: 400max-wait: 8000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000num-tests-per-eviction-run: 3test-while-idle: truetest-on-borrow: truetest-on-return: falsekeep-alive: truepool-prepared-statements: truemax-pool-prepared-statement-per-connection-size: 20filters: statfilter:stat:slow-sql-millis: 500use-global-data-source-stat: trueconnection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000qywx:driver-class-name: com.mysql.cj.jdbc.Driver username: xyzpassword: 123456url: jdbc:mysql://1.2.3.4:3306/qyweixing?autoReconnect=true&failOverReadOnly=false&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghaivalidation-query: SELECT 1initial-size: 30min-idle: 30max-active: 400max-wait: 8000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000num-tests-per-eviction-run: 3test-while-idle: truetest-on-borrow: truetest-on-return: falsekeep-alive: truepool-prepared-statements: truemax-pool-prepared-statement-per-connection-size: 20filters: statfilter:stat:slow-sql-millis: 500use-global-data-source-stat: trueconnection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
解决办法中 druid 配置参数说明:
| 属性 | 默认值 | 备注 |
|---|---|---|
| testOnBorrow | false | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
| testOnBorrow | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
| testWhileIdle | true | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
| timeBetweenEvictionRunsMillis | 单位毫秒 | 有两个含义:1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
| validationQuery | 用来测试连接是否可用的SQL语句 | |
| minEvictableIdleTimeMillis | 1000L * 60L * 30L | 连接空闲时间大于该值并且池中空闲连接大于minIdle则关闭该连接 。默认30分钟 |
| keepAlive | false | 保持连接的有效性,也就是跟数据库续租,只有空闲时间大于keepAliveBetweenTimeMillis并且小于minEvictableIdleTimeMillis该参数才会有用 |
连接池配置文件中以上参数都有进行配置,但是程序还是有报错;可以根据报错日志,错定位所使用的连接池,然后定位对应连接池创建的代码,看看是否是创建连接池的时候缺了以上对应的参数配置。
关键点:
为什么 validation-query 需要放在每个数据源下?
Druid 可以管理多个数据源,每个数据源可能连接到不同的数据库,因此每个数据源的配置可能不同。比如:
如果你放在全局 druid 下,它可能只会对默认数据源有效,而其他数据源就会忽略掉这个配置。
总结:
这样就能确保每个数据源在获取连接时,都能根据相应的数据库类型进行有效性验证。
希望这次解释清楚了!如果有更多问题,随时告诉我。
-
validation-query:需要放在每个数据源(如druid.master、druid.order)的配置下。每个数据源可能有不同的验证需求。 -
test-on-borrow、test-while-idle:建议这两个选项都启用,以确保在借用连接和空闲时都进行有效性验证。 -
Oracle 数据库:通常使用
SELECT 1 FROM DUAL来验证连接。 -
MySQL 数据库:通常使用
SELECT 1来验证连接。 -
在你的场景下,配置应该放在每个数据源的级别下,例如
druid.master、druid.order等。 -
validation-query应该针对每个数据源配置,不是全局配置。