mysql连接未释放,导致无法进行DB操作(长连接及短连接)
发布日期:2021-07-20 20:53:14 浏览次数:33 分类:技术文章

本文共 5843 字,大约阅读时间需要 19 分钟。

相关连接: show processlist 分析:

长连接相关:

项目运行时抛出异常:

org.hibernate.exception.GenericJDBCException: Could not open connection	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)	at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:221)	at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157)	at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:67)	at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:160)	at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1425)	at com.sf.iec.common.dao.BaseDao.saveOrUpdateByBatch(BaseDao.java:268)	at com.sf.iec.operationbusiness.manifest.dao.impl.ManifestDaoImpl.insetPostManifestFailLog(ManifestDaoImpl.java:2284)	at com.sf.iec.operationbusiness.manifest.service.impl.ManifestServiceImpl.pushAcpInfo(ManifestServiceImpl.java:4763)	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)	at java.lang.reflect.Method.invoke(Method.java:597)	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)	at com.sun.proxy.$Proxy152.pushAcpInfo(Unknown Source)	at com.sf.iec.common.thread.AcpInfoPushRunnable$1.handler(AcpInfoPushRunnable.java:40)	at com.sf.iec.common.util.BatchHandlerList.handlerList(BatchHandlerList.java:44)	at com.sf.iec.common.thread.AcpInfoPushRunnable.run(AcpInfoPushRunnable.java:47)	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)	at java.lang.Thread.run(Thread.java:662)Caused by: java.sql.SQLException: Couldn't get connection because we are at maximum connection count (100/100) and there are none available	at org.logicalcobwebs.proxool.Prototyper.quickRefuse(Prototyper.java:309)	at org.logicalcobwebs.proxool.ConnectionPool.getConnection(ConnectionPool.java:152)	at org.logicalcobwebs.proxool.ProxoolDataSource.getConnection(ProxoolDataSource.java:97)	at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141)	at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292)	at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214)	... 26 more

用  show full processlist 语句发现本机IP已经使用了100个DB连接(均为sleep状态)

相关 sql:

select SUBSTRING_INDEX(host,':',1) as ip , count(*) from information_schema.processlist group by ip;show full processlist;show status;show GLOBAL VARIABLES like '%wait_timeout%'

其实是baseDAO的代码问题, session.close()没有放到finally里面  导致前面语句插入失败时没有提交事务 也没有释放连接:

错误代码:

public void saveByBatch(List
list ,int batchSize){ if(!CollectionUtil.isEmpty(list)){ Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); int i=0; for (T entity:list ) { i++; session.save(entity); if ( i % batchSize == 0 ) { session.flush(); session.clear(); } tx.commit(); session.close(); } }

睡眠连接过多 解决方法

睡眠连接过多,会对mysql服务器造成什么影响?

严重消耗mysql服务器资源(主要是cpu, 内存),并可能导致mysql崩溃。

造成睡眠连接过多的原因?

1. 使用了太多持久连接(个人觉得,在高并发系统中,不适合使用持久连接)

2. 程序中,没有及时关闭mysql连接
3. 数据库查询不够优化,过度耗时。

那么,如果要从根本上解决sleep连接过多,就得从以上三点反复检查,但是见效并不快。

网上有人分享,使用shell脚本配合cron,定期杀死睡眠时间太久的连接,但是这种方法非常不可取,典型的以暴制暴,很可能导致数据崩溃,而且,还需要编写相应shell, 设置cron, 实施成本较繁琐,不推荐使用。

那么更好的办法应该是让mysql自己决定这些睡眠连接的命运,实施会更简单,有效。

mysql的配置文件中,有一项:
wait_timeout, 即可设置睡眠连接超时秒数,如果某个连接超时,会被mysql自然终止,多好的办法!

如设置: 

wait_timeout=100 #即设置mysql连接睡眠时间为100秒,任何sleep连接睡眠时间若超过100秒,将会被mysql服务自然终止,要比编写shell脚本更简单。

那么,对于正在运行中的生产服务器,在不能停止服务情况下,修改此项怎么办?很简单,以root用户登录到mysql,执行:

set global wait_timeout=100

# vi /etc/my.cnf  [mysqld]  wait_timeout=10  # /etc/init.d/mysql restart
  • 1

不过这个方法太生硬了,线上服务重启无论如何都应该尽可能避免,看看如何在MySQL命令行里通过SET来设置:

mysql> set global wait_timeout=10;  mysql> show global variables like '%timeout';  +----------------------------+-------+  | Variable_name | Value |  +----------------------------+-------+  | wait_timeout | 10 |  +----------------------------+-------+
  • 1

即可。

在我的生产环境中,使用这个办法,取得了相当好的效果。

当然,更根本的方法,还是从以上三点排查之:

1. 程序中,不使用持久链接,即使用mysql_connect而不是pconnect。
2. 程序执行完毕,应该显式调用mysql_close
3. 只能逐步分析系统的SQL查询,找到查询过慢的SQL,优化之

wait_timeout默认值:

这里写图片描述
interactive_timeout默认值:
这里写图片描述

sql命令:

SHOW GLOBAL VARIABLES LIKE 'wait_timeout';SHOW GLOBAL VARIABLES LIKE 'interactive_timeout';set global wait_timeout=30;SET GLOBAL interactive_timeout=30;
  •  

小注:wait_timeout要与interactive_timeout一起修改才能起效。

这种修改方式在重启mysql服务后,会失效,所以最好还是把这两个属性配置到mysql配置文件中。

转载地址:https://blog.csdn.net/liao0801_123/article/details/82690863 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:webService中获取request和response对象
下一篇:web前端之闭包

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月06日 05时50分07秒