mysql连接未释放,导致无法进行DB操作(长连接及短连接)

相关连接: show processlist 分析:http://blog.chinaunix.net/uid-134240-id-220211.html

长连接相关:https://www.cnblogs.com/wangtao_20/p/4783524.html

项目运行时抛出异常:

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<T> 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配置文件中。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值