最近这段时间,现网突然频繁的报连不上数据库No operations allowed after connection closed。

2021-11-03 10:40:32.750 [TID:11458.146.16359072327350221] [http-nio-1192-exec-8] 
WARN  com.zaxxer.hikari.pool.PoolBase -DatebookHikariCP - 
Failed to validate connection com.mysql.jdbc.JDBC4Connection@5d5e3f2a 
(No operations allowed after connection closed.).
 Possibly consider using a shorter maxLifetime value.
message:2021-11-02 22:25:28.900 [TID:11422.86.16358631288741127] [http-nio2-8089-exec-62] ERROR c.m.j.base.aspect.ExceptionAspect -
org.springframework.jdbc.UncategorizedSQLException: ### Error querying database. Cause: java.sql.SQLException: No operations allowed after connection closed.
### The error may exist in class path resource [mapper/home/HomePageMapper.xml] ### The error may involve defaultParameterMap ### The error occurred while setting parameters ### SQL: 
/*!mycat: schema=student*/SELECT count(0) FROM education_class ec INNER JOIN education_student_learn_history eslh ON ec.id = eslh.class_id AND eslh.RENT_ID = 304 WHERE 1 = 1 AND eslh.type = 0 AND eslh.new_sign = 1 AND from_unixtime(eslh.again_study_faker_time / 1000, '%Y-%m-%d') < ? AND ec.manager_id = ? AND ec.RENT_ID = 304 
### Cause: java.sql.SQLException: No operations allowed after connection closed. ; uncategorized SQLException; SQL state [HY000]; error code [0];
 No operations allowed after connection closed.; nested exception is java.sql.SQLException: No operations allowed after connection closed. 
org.springframework.jdbc.UncategorizedSQLException: ### Error querying database. Cause: java.sql.SQLException: No operations allowed after connection closed. 
### The error may exist in class path resource [mapper/home/HomePageMapper.xml] ### The error may involve defaultParameterMap 
### The error occurred while setting parameters ### SQL: 
/*!mycat: schema=student*/SELECT count(0) FROM education_class ec INNER JOIN education_student_learn_history eslh ON ec.id = eslh.class_id AND eslh.RENT_ID = 304 WHERE 1 = 1 AND eslh.type = 0 AND eslh.new_sign = 1 AND from_unixtime(eslh.again_study_faker_time / 1000, '%Y-%m-%d') < ? AND ec.manager_id = ? AND ec.RENT_ID = 304 
### Cause: java.sql.SQLException: No operations allowed after connection closed. ; uncategorized SQLException; SQL state [HY000]; error code [0]; 
No operations allowed after connection closed.; nested exception is java.sql.SQLException: No operations allowed after connection closed. at 
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:89) at 
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at 
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at 
org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy.$Proxy119.selectList(Unknown Source) at 
org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230) at 
org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:128) at 
org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:68) at 
org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53) at 
com.sun.proxy.$Proxy380.putDownData(Unknown Source) at sun.reflect.GeneratedMethodAccessor2247.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy381.putDownData(Unknown Source) at com.msedu.jiaowu.home.service.HomePageService.putDownData(HomePageService.java:342) at

出现该错误的来源多个服务多个入口,所以不太可能是某个业务代码改动导致的,更可能是相关数据库配置导致的

该问题实际上就是java代码内请求使用了一个已被关闭了的mysql连接

之所以会出现这个异常,是因为MySQL5.0以后针对超长时间DB连接做了一个处理,那就是如果一个DB连接在无任何操作情况下过了8个小时后(Mysql 服务器默认的“wait_timeout”是8小时),Mysql会自动把这个连接关闭。这就是问题的所在,在连接池中的connections如果空闲超过8小时,mysql将其断开,而Java的数据库连接池自己并不知道该connection已经失效,如果这时有 Client请求connection,连接池将该失效的Connection提供给Client,将会造成上面的异常。
所以配置datasource时需要配置相应的连接池参数

查看了下现有服务的数据库连接池配置(项目用了apollo)

再看下mysql对应的wait_timeout配置

show VARIABLES

Variable_name Value
wait_timeout 30(s)
interactive_timeout 120(s)

可以看到java连接池设置的max-lifetime(一个connection在连接池中的存活时间,默认是1800000,即30分钟。如果设置为0,表示存活时间无限大。如果不等于0且小于30秒则会被重置回30分钟)为30分钟,而mysql那边的有效期时间却是30s,

也就是当连接池中保持着这个连接,未超过连接池配置的30分钟,但超过了mysql的30s,MySQL 就会断开该连接,而连接池则以为该被断开的连接依然有效。在这种情况下,如果客户端代码向连接池请求连接的话,连接池就会把已经失效的连接返回给客户端,客户端在使用该失效连接的时候即抛出异常

三、解决方案

1、调大mysql的wait_timeout和interactive_timeout。

修改为2个小时timeout,保证mysql的wait_timeout>连接池的max-lifetime

Variable_name Value
wait_timeout 7200(s)
interactive_timeout 7200(s)

遇到问题的时候,修改配置有时候也要考虑,调整相关配置是否会带来其他的影响?

比如当前业务高峰期时mysql_connection是多少?保留多久connection在高峰期都不会撑爆你数据库连接池?
如果你知道这个池-那么是改mysql ?还是改连接池配置?还是双管齐下都是有据可循且不会带来后遗症的-最佳解决方案

比如当前有环境,一个现网的后台管理系统,使用人数在50以内,那么我wait_timeout 就是默认8小时,hikari连接池不用做连接有效性检查等,都是万事ok的。

而我还有一个面向C端用户的用户端平台,用户量在300万以内,如果我wait_timeout为8小时,那我一到高峰期肯定就是死翘翘的,会有太多的TCP连接没关闭,数据库连接数肯定是不够的。

因此对于连接池的设置,以及mysql数据库配置,应该相辅相成,结合着现实情况设置,而不是直接一波输出改完就完事,不要解决了A问题,却引入了B问题。

五、扩展(Hikari连接池配置作用)

配置项 描述 构造器默认值 默认配置validate之后的值 validate重置
autoCommit 自动提交从池中返回的连接 true true -
connectionTimeout 等待来自池的连接的最大毫秒数 SECONDS.toMillis(30) = 30000 30000 如果小于250毫秒,则被重置回30秒
idleTimeout 连接允许在池中闲置的最长时间 MINUTES.toMillis(10) = 600000 600000 如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,则会被重置为0(代表永远不会退出);如果idleTimeout!=0且小于10秒,则会被重置为10秒
maxLifetime 池中连接最长生命周期 MINUTES.toMillis(30) = 1800000 1800000 如果不等于0且小于30秒则会被重置回30分钟
connectionTestQuery 如果您的驱动程序支持JDBC4,我们强烈建议您不要设置此属性 null null -
minimumIdle 池中维护的最小空闲连接数 -1 10 minIdle<0或者minIdle>maxPoolSize,则被重置为maxPoolSize
maximumPoolSize 池中最大连接数,包括闲置和使用中的连接 -1 10 如果maxPoolSize小于1,则会被重置。当minIdle<=0被重置为DEFAULT_POOL_SIZE则为10;如果minIdle>0则重置为minIdle的值
metricRegistry 该属性允许您指定一个 Codahale / Dropwizard MetricRegistry 的实例,供池使用以记录各种指标 null null -
healthCheckRegistry 该属性允许您指定池使用的Codahale / Dropwizard HealthCheckRegistry的实例来报告当前健康信息 null null -
poolName 连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置 null HikariPool-1 -
initializationFailTimeout 如果池无法成功初始化连接,则此属性控制池是否将 fail fast 1 1 -
isolateInternalQueries 是否在其自己的事务中隔离内部池查询,例如连接活动测试 false false -
allowPoolSuspension 控制池是否可以通过JMX暂停和恢复 false false -
readOnly 从池中获取的连接是否默认处于只读模式 false false -
registerMbeans 是否注册JMX管理Bean( MBeans false false -
catalog 为支持 catalog 概念的数据库设置默认 catalog driver default null -
connectionInitSql 该属性设置一个SQL语句,在将每个新连接创建后,将其添加到池中之前执行该语句。 null null -
driverClassName HikariCP将尝试通过仅基于jdbcUrl的DriverManager解析驱动程序,但对于一些较旧的驱动程序,还必须指定driverClassName null null -
transactionIsolation 控制从池返回的连接的默认事务隔离级别 null null -
validationTimeout 连接将被测试活动的最大时间量 SECONDS.toMillis(5) = 5000 5000 如果小于250毫秒,则会被重置回5秒
leakDetectionThreshold 记录消息之前连接可能离开池的时间量,表示可能的连接泄漏 0 0 如果大于0且不是单元测试,则进一步判断:(leakDetectionThreshold < SECONDS.toMillis(2) or (leakDetectionThreshold > maxLifetime && maxLifetime > 0),会被重置为0 . 即如果要生效则必须>0,而且不能小于2秒,而且当maxLifetime > 0时不能大于maxLifetime
dataSource 这个属性允许你直接设置数据源的实例被池包装,而不是让HikariCP通过反射来构造它 null null -
schema 该属性为支持模式概念的数据库设置默认模式 driver default null -
threadFactory 此属性允许您设置将用于创建池使用的所有线程的java.util.concurrent.ThreadFactory的实例。 null null -
scheduledExecutor 此属性允许您设置将用于各种内部计划任务的java.util.concurrent.ScheduledExecutorService实例 null null -
一、背景最近这段时间,现网突然频繁的报连不上数据库No operations allowed after connection closed。2021-11-03 10:40:32.750 [TID:11458.146.16359072327350221] [http-nio-1192-exec-8] WARN com.zaxxer.hikari.pool.PoolBase -DatebookHikariCP - Failed to validate connection com.mysql
No operation s allowed after connection clo sed 问题 小记 Spring Boot 2.x 数据库 连接 池默认 Hikari ,现有配置为默认配置 日志是warn级别的: Failed to validate connection com. mysql .cj.jdbc. Connection Impl@70ec1a35 (No operation s allowed after connection clo sed .). Possibly consider us
最近使用 Mysql 操作数据库,在Servlet里面调用之后 出现了No operation s allowed after connection clo sed . 问题 。 出现这个 问题 一般出现在多次刷新页面的情况下面。 使用debug进行错误排查的时候,他的报错是在 pst = con.prepareStatement(sql); 当我把这个变成非静态之后, 问题 没有解决,最后才定位到Connectio...
常遇到的几种错误 Possibly consider using a shorter max Lifetime value Connection is not available, request timed out after xxxxxms No operation s allowed after connection clo sed 常见配置及注释说明,可以使用并根据说明调整 首先确认网络 问题 max imum-pool-size建议值 minimum- idle idle - timeout max -l
1. 在交互模式下,session级别的 interactive_ timeout 继承了global级别 interactive_ timeout 。 2. 在交互模式下, 连接 时长受interactive_ timeout 影响。 3. 在非交互模式下,session级别的 wait _ timeout ,继承了global级别 wait _ timeout 。 4. 在非交互模式下, 连接 时长受 wait _ timeout 影响。 5. 在交互模式下,session级别的 wait _ timeout ,继承了global级别int
使用 mysql +cp30 连接 池时,报错No operation s allowed after connection clo sed 。从报错信息来看,是 connection 断开导致的错误。在网上搜索后发现,较新版本的 mysql 配置了 connection 的默认时间,默认时间一般为8个小时。超过了八个小时, mysql 则会自动断开 connection ,解决方法为: 在xml文件中增加property配置 ### Error querying database. Cause: java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]'@P1' 附近有语法错误。 ### The error may exist in xxxx ### The error may involve xxx ### The error o
Spring Boot多数据源配置及No operation s allowed after connection clo sed 连接 异常的解决 最近项目上线,遇到了一个诡异的bug。 首先说下我的项目配置: SpringBooot + SpringMVC+SpringData JPA+ 两个 MySql 也就是我这个项目配置了多数据源。 前期开发是没什么 问题 的,一切运转良好。 但是等到项目上线...
出现异常的原因: Mysql 在5以后针对超长时间DB 连接 做了一个处理, Mysql 服务器默认的“ wait _ timeout ”是8小时,也就是说一个 connection 空闲超过8个小时, Mysql 将自动断开该 connection 。所以使用 连接 池的时候虽然 连接 对象还在但是链接数据库的时候会一直报这个异常。 解决办法: 进入 MySQL 查看设置的时间,show global variables like ‘ wait _ timeout ’; 1、增加 MySQL wait _ timeout 的时间 windows环境下,修改m
mysql 执行报错:Error querying database. Cause: java.sql.SQLSyntaxErrorException:which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 1.这个错误发生在 mysql 5.7 版本及以上版本会出现的 问题 mysql 5.7版本默认的sql配置是:s