最近这段时间,现网突然频繁的报连不上数据库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