相关连接: 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配置文件中。