数据库链接超时(默认8小时)报错:MySQLNonTransientConnectionException

7 篇文章 1 订阅
6 篇文章 0 订阅

myBatis连接MySQL报异常:No operations allowed after connection closed.Connection was implicitly closed

 

异常信息

?
mybatis错误如下:

HTTP Status 500 - Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: 

Could not open JDBC Connection for transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.


type Exception report

message Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection 

for transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.

description The server encountered an internal error that prevented it from fulfilling this request.

exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is
	org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is 
	com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

root cause

org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is 
	com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
	org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:243)
	org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
	org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:420)
	org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:257)
	org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
	org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
	com.sun.proxy.$Proxy24.news(Unknown Source)
	com.cn.article.controller.ArticleInfoController.news2(ArticleInfoController.java:691)
	sun.reflect.GeneratedMethodAccessor171.invoke(Unknown Source)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	java.lang.reflect.Method.invoke(Method.java:601)
	org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
	org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
	org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:690)
	org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

root cause

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 50,614,951 milliseconds ago.  
	The last packet sent successfully to the server was 50,614,951 milliseconds ago. is longer than the server configured value of 'wait_timeout'.
	You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured 
	values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
	sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	java.lang.reflect.Constructor.newInstance(Constructor.java:525)
	com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
	com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1127)
	com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3983)
	com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2596)
	com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776)
	com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2832)
	com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2781)
	com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1569)
	com.mysql.jdbc.DatabaseMetaData.getUserName(DatabaseMetaData.java:7013)
	org.apache.commons.dbcp.DelegatingConnection.toString(DelegatingConnection.java:104)
	org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.toString(PoolingDataSource.java:344)
	java.lang.String.valueOf(String.java:2854)
	java.lang.StringBuilder.append(StringBuilder.java:128)
	org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:207)
	org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
	org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:420)
	org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:257)
	org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
	org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
	com.sun.proxy.$Proxy24.news(Unknown Source)
	com.cn.article.controller.ArticleInfoController.news2(ArticleInfoController.java:691)
	sun.reflect.GeneratedMethodAccessor171.invoke(Unknown Source)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	java.lang.reflect.Method.invoke(Method.java:601)
	org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
	org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
	org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:690)
	org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)


hibernate错误如下:
org.hibernate.exception.JDBCConnectionException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java: 74 )
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java: 43 )
.......
Caused by: com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception/error:
** BEGIN NESTED EXCEPTION **
com.mysql.jdbc.CommunicationsException
MESSAGE: Communications link failure due to underlying exception:
** BEGIN NESTED EXCEPTION **
java.net.SocketException
MESSAGE: Broken pipe
STACKTRACE:
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
......
** END NESTED EXCEPTION **

原因分析

查看了Mysql的文档,以及Connector/J的文档以及在线说明发现,出现这种异常的原因是:

  Mysql服务器默认的“wait_timeout”是8小时,也就是说一个connection空闲超过8个小时,Mysql将自动断开该connection。这就是问题的所在,在C3P0 pools中的connections如果空闲超过8小时,Mysql将其断开,而C3P0并不知道该connection已经失效,如果这时有Client请求connection,C3P0将该失效的Connection提供给Client,将会造成上面的异常。

解决方案

解决的方法有3种:

  1. 增加 wait_timeout 的时间。
  2. 减少 Connection pools 中 connection 的 lifetime。
  3. 测试 Connection pools 中 connection 的有效性。
  4. 自己最终解决:将原来的DBCP连接池改为C3p0连接池,并增c3p0对于maxIdleTime时间的控制,一定要小于8小时

当然最好的办法是同时综合使用上述方法,下面就 DBCP、C3P0 和 simple jdbc dataSource 分别做一说明,假设 wait_timeout 为

默认的8小时

DBCP 增加以下配置信息:

复制代码
validationQuery = "select 1"

testWhileIdle = "true"

//some positive integer
timeBetweenEvictionRunsMillis = 3600000

//set to something smaller than 'wait_timeout'
minEvictableIdleTimeMillis = 18000000

//if you don't mind a hit for every getConnection(), set to "true"
testOnBorrow = "true"
复制代码

C3P0 增加以下配置信息:

复制代码
//获取connnection时测试是否有效
testConnectionOnCheckin = true

//自动测试的table名称
automaticTestTable=C3P0TestTable

//set to something much less than wait_timeout, prevents connections from going stale
idleConnectionTestPeriod = 18000

//set to something slightly less than wait_timeout, preventing 'stale' connections from being handed out
maxIdleTime = 25000

//if you can take the performance 'hit', set to "true"
testConnectionOnCheckout = true

c3p0配置

(推荐)

使用第三方数据库连接池: 现在第三方数据库连接池使用较多的为c3p0,proxool等,在性能上c3p0稍好一些,原因c3p0数据库连接池,

底层有一个定时查看数据库连接是否有效的参数。而且Hibernate的api中也推荐使用第三方数据库连接池,

因为Hibernate本身的数据库连接池过于简单、本身存在bug。c3p0参数配置如下:

<!-- lang: xml -->
<!-- 数据源 --> 
<bean id="dataSourceTarget" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="user" value="root" />
<property name="password" value="root" />
<property name="jdbcUrl" value="jdbc:mysql://192.168.61.208:3306/sinoomv1_0_0" />
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<!-- 系统初始化连接数 -->
<property name="initialPoolSize" value="10" />
<!-- 最大连接数 -->
<property name="maxPoolSize" value="30" />
<!-- 最小连接数 -->
<property name="minPoolSize" value="10" />
<!--最大空闲时间,600秒(10分钟)内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="600" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->  
<property name="acquireIncrement" value="3" />
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->  
<property name="idleConnectionTestPeriod" value="60" />
<!-- 每次从pool内checkout连接时测试有效性(同步操作)
    程序每次数据库调用都连接有效性,若无效关闭此连接并剔除出pool,
   从pool内取其他连接,慎用,会造成至少多一倍的数据库调用。Default:false -->
<property name="testConnectionOnCheckout" value="false" />
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts" value="30"/>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay" value="1000"/>
</bean>

查看mysql数据库连接池情况,命令如下:

<!-- lang: sql -->
Mysql> show processlist;

ps:最近在在停起程序的时候我发现了一个问题,就算是我停止了服务,但是程序和mysql数据库之间的连接数依然没有断开,

后来经查资料和同事请教,我发现在上边的c3p0配置存在一个小bug。因为我将c3p0交给spring进行管理,

但是在上边注入的bean中没有加上destroy-method="close"这个属性。 也就是说Spring是不能正常销毁连接的,由此出现了我说的问题。

写在这里以供大家警示,真是马虎啊,竟然忘记了销毁,实在不应该。

<!-- lang: xml -->
<!-- 数据源 --> 
<bean id="dataSourceTarget" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
 ... ...
</bean>

4.自己实际解决方案:

4.1Spring整合c3p0 配置文件Demo如下:

  1. <?xml version="1.0" encoding="UTF-8"?>    
  2. <beans xmlns="http://www.springframework.org/schema/beans"    
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  4.     xmlns:jee="http://www.springframework.org/schema/jee"    
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd    
  6.             http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">    
  7.     <bean id="dataSource"    
  8.         class="com.mchange.v2.c3p0.ComboPooledDataSource"    
  9.         destroy-method="close">    
  10.         <property name="driverClass">    
  11.             <value>com.mysql.jdbc.Driver</value>    
  12.         </property>    
  13.         <property name="jdbcUrl">    
  14.             <value>jdbc:mysql://192.168.3.110:3306/DBName?useUnicode=true&characterEncoding=GBK</value>    
  15.         </property>    
  16.         <property name="user">    
  17.             <value>root</value>    
  18.         </property>    
  19.         <property name="password">    
  20.             <value>root</value>    
  21.         </property>    
  22.      
  23.  <!--连接池中保留的最小连接数。-->    
  24.         <property name="minPoolSize">    
  25.             <value>5</value>    
  26.         </property>    
  27.      
  28.  <!--连接池中保留的最大连接数。Default: 15 -->    
  29.         <property name="maxPoolSize">    
  30.             <value>30</value>    
  31.         </property>    
  32.      
  33. <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->    
  34.         <property name="initialPoolSize">    
  35.             <value>10</value>    
  36.         </property>    
  37.      
  38.  <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->    
  39.         <property name="maxIdleTime">    
  40.             <value>60</value>    
  41.         </property>    
  42.      
  43.  <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->    
  44.         <property name="acquireIncrement">    
  45.             <value>5</value>    
  46.         </property>    
  47.      
  48.  <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements    
  49.   属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。    
  50.   如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->    
  51.         <property name="maxStatements">    
  52.             <value>0</value>    
  53.         </property>    
  54.      
  55.  <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->    
  56.         <property name="idleConnectionTestPeriod">    
  57.             <value>60</value>    
  58.         </property>    
  59.      
  60.  <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->    
  61.         <property name="acquireRetryAttempts">    
  62.             <value>30</value>    
  63.         </property>    
  64.      
  65.  <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效    
  66.   保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试    
  67.   获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->    
  68.         <property name="breakAfterAcquireFailure">    
  69.             <value>true</value>    
  70.         </property>    
  71.      
  72.  <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的    
  73.   时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable    
  74.   等方法来提升连接测试的性能。Default: false -->    
  75.         <property name="testConnectionOnCheckout">    
  76.             <value>false</value>    
  77.         </property>    
  78.     </bean>    
  79. </beans>   

 4.2Maven的pom.xml文件中引入c3p0依赖:

<!-- 数据库连接池包-->      <dependency>          <groupId>com.mchange</groupId>          <artifactId>c3p0</artifactId>          <version>0.9.5-pre8</version>      </dependency>  注意:可以配置最大空闲时间小一些如下60秒

  1. <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->    
  2.         <property name="maxIdleTime">    
  3.             <value>60</value>    
  4.         </property>  

4.3 在项目日志文件中配置debug模式,其中DEBUG模式下可能会报java.io.FileNotFoundException错误信息(说c3p0找不到c3p0.properties;mchange-log.properties;mchange-commons.properties等文件),这是因为在DEBUG模式下c3p0会打印出具体的警告信息(这不是报错,这是警告信息,不影响运行),其中c3p0官方推荐INFO级别日志打印级别。在eclipse控制台中便可以查看c3p0数据库连接池中连接的获取(默认最少有5个空闲,name一分钟之内有五个connection被废除)和废除情况,这样就可以保持Spring维护的数据库连接池中的连接都是最新的。输出如下:

[com.mchange.v2.c3p0.impl.NewPooledConnection] - com.mchange.v2.c3p0.impl.NewPooledConnection@369d34 closed by a client. java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:659) at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:255) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:621) at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1024) at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696) [com.mchange.v2.resourcepool.BasicResourcePool] - incremented pending_acquires: 2 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool] - Preparing to destroy PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@1908897 [com.mchange.v2.resourcepool.BasicResourcePool] - Starting acquisition series. Incremented pending_acquires [2],  attempts_remaining: 30 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool] - Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@369d34 [com.mchange.v2.c3p0.impl.NewPooledConnection] - com.mchange.v2.c3p0.impl.NewPooledConnection@3b21e3 closed by a client. java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:659) at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:255) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:621) at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1024) at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696) [com.mchange.v2.async.ThreadPoolAsynchronousRunner] - com.mchange.v2.async.ThreadPoolAsynchronousRunner@1641371: Adding task to queue -- com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@c6a83d [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool] - Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@3b21e3 [com.mchange.v2.resourcepool.BasicResourcePool] - Successfully destroyed resource: com.mchange.v2.c3p0.impl.NewPooledConnection@369d34 [com.mchange.v2.resourcepool.BasicResourcePool] - Successfully destroyed resource: com.mchange.v2.c3p0.impl.NewPooledConnection@3b21e3 [com.mchange.v2.resourcepool.BasicResourcePool] - incremented pending_acquires: 3 [com.mchange.v2.c3p0.impl.NewPooledConnection] - com.mchange.v2.c3p0.impl.NewPooledConnection@1908897 closed by a client. java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:659) at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:255) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:621) at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1024) at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)

simple jdbc dataSource 增加以下配置信息:

复制代码
Pool.PingQuery = select 1

Pool.PingEnabled = true

Pool.PingConnectionsOlderThan = 0

//对于空闲的连接一个小时检查一次
Pool.PingConnectionsNotUsedFor = 3600000
复制代码

其他方案(不推荐)

  对于 MySQL5 之前的版本,如 Mysql4.x,只需要修改连接池配置中的 URL,添加一个参数:autoReconnect=true(如jdbc:mysql://hostaddress:3306/schemaname?autoReconnect=true),如果是 MySQL5 及以后的版本,则需要修改 my.cnf(或者my.ini) 文件,在 [mysqld] 后面添加上:

?
wait_timeout = n
interactive-timeout = n

其中 n 为服务器关闭交互式连接前等待活动的秒数。可是就部署而言每次修改 my.ini 比较麻烦,而且 n 等于多少才是合适的值呢? 所以并不推荐这个解决办法。)

 

hibernate的解决方案: 
<property name="connection.autoReconnect">true</property>  <!--这个是最主要的--> 
<property name="connection.autoReconnectForPools">true</property> 
<property name="connection.is-connection-validation-required">true</property> 
加入以上property,可解决此问题,如果未使用hibernate等持久化管理框架,可在mysql的url中加入autoReconnect=true,这样就可以解决。
原 因很简单。在对数据库操作结束后关闭连接是正确的做法,没什么大问题。至于出现:No operations allowed after connection closed。这样的问题原因只有一个,你这里和数据库的连接Connection是一个Static的,程序共享这一个Connection。所以第一 次对数据库操作没问题,当把Connection关闭后,第二次还想操作数据库时Connection肯定不存在了。



-------------------------相关-------------------------

 

1. 即使在创建Mysql时url中加入了autoReconnect=true参数,一但这个连接两次访问数据库的时间超出了服务器端wait_timeout的时间限制,还是会CommunicationsException: The last packet successfully received from the server was xxx milliseconds ago. 
2. 服务器端的参数可以用 
  show global variables like 'wait_timeout'; 
  set global wait_timeout=10; 
  来进行设置,但是wait_timeout值不应该设的太高. 
3. 较好的策略是对处于idle状态的connection定时发送一个sql,来刷新服务器上的时间戳.这可以使用c3p0r的连接池.http://bzhang.iteye.com/blog/321832 
4. 对于tomcat的server.xml中使用的连接池,http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html,http://commons.apache.org/dbcp/configuration.html使用DBCP的连接池可以采用 
<Resource name="jdbc/test" auth="Container"  
              type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver"  
              url="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"  
              username="root" password="test" maxActive="500" maxIdle="10"  
              maxWait="-1" timeBetweenEvictionRunsMillis="10000" minEvictableIdleTimeMillis="10000" /> 
  4.1 设置validationQuery,这样每次borrow(默认为开启)时会通过这个sql校验连接的有效性,但是增加了时间. 
  4.2 设置timeBetweenEvictionRunsMillis="10000" minEvictableIdleTimeMillis="10000" 依赖evictor thread线程来把超时的连接关闭. 
  4.3 设置testWhileIdle="true" timeBetweenEvictionRunsMillis="10000" validationQuery="select 1" 使得定时去用query检测处于idle状态的连接,也就刷新了服务器端的时间. 

5.每次提交的最大packet大小 
show global variables like 'max_allowed_packet'; 
set global max_allowed_packet=1024*1024; 

6. SQLyog 中连接参数的设置 
  6.1 在SQLyog中的设置 set autocommit=0,这样当前连接的自动提交为false,可以控制事务了. 
  6.2 begin; 事务开始 
  6.3 select * from test where 1=1 and id =1 for update;这样就把选到的记录行锁上了,再开一个SQLyog,也执行以上相同的操作,就会一直wait在那里. 
  6.4 commit; 提交 
  6.5 rollback; 回滚 
  6.6 set autocommit=0;后应该加上 
      set transaction isolation level read committed; 
      这样其它客户端就能看到commit的数据, 
  疑问: 
      如果不设置set transaction isolation level read committed;如果两个客户端都select 相同的数据,一个客户端修改然后提交,另一个客户端不提交当前事务的前提下,去执行select ,取不到另一客户端提交的数据,不知道SQLyog默认的事务级别是什么样的. 

7. SQLyog中查看mysql的状态,show global variables like '%lock%'; 是个好方法.对于事务锁(例如for update)报Lock wait timeout exceeded ,只能通过修改my.ini文件innodb_lock_wait_timeout = 100;才能生效. 

8. linux下修改用户密码 mysqladmin -u root password "new_pass"


三大连接池说明:

1. Apache-DBCP

BasicDataSource 相关的参数说明

dataSource: 要连接的 datasource (通常我们不会定义在 server.xml)
defaultAutoCommit: 对于事务是否 autoCommit, 默认值为 true
defaultReadOnly: 对于数据库是否只能读取, 默认值为 false
driverClassName:连接数据库所用的 JDBC Driver Class,
maxActive: 可以从对象池中取出的对象最大个数,为0则表示没有限制,默认为8
maxIdle: 最大等待连接中的数量,设 0 为没有限制 (对象池中对象最大个数)
minIdle:对象池中对象最小个数
maxWait: 最大等待秒数, 单位为 ms, 超过时间会丟出错误信息
password: 登陆数据库所用的密码
url: 连接数据库的 URL
username: 登陆数据库所用的帐号
validationQuery: 验证连接是否成功, SQL SELECT 指令至少要返回一行
removeAbandoned: 是否自我中断, 默认是 false
removeAbandonedTimeout: 几秒后会自我中断, removeAbandoned 必须为 true
logAbandoned: 是否记录中断事件, 默认为 false
minEvictableIdleTimeMillis:大于0 ,进行连接空闲时间判断,或为0,对空闲的连接不进行验证;默认30分钟
timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程,默认-1
testOnBorrow:取得对象时是否进行验证,检查对象是否有效,默认为false
testOnReturn:返回对象时是否进行验证,检查对象是否有效,默认为false
testWhileIdle:空闲时是否进行验证,检查对象是否有效,默认为false


在使用DBCP的时候,如果使用默认值,则数据库连接因为某种原因断掉后,再从连接池中取得连接又不进行验证,这时取得的连接实际上就会是无效的数据库连接。因此为了防止获得的数据库连接失效,在使用的时候最好保证:


username: 登陆数据库所用的帐号
validationQuery:SELECT COUNT(*) FROM DUAL
testOnBorrow、testOnReturn、testWhileIdle:最好都设为true
minEvictableIdleTimeMillis:大于0 ,进行连接空闲时间判断,或为0,对空闲的连接不进行验证
timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程
PS:在构造GenericObjectPool [BasicDataSource在其createDataSource () 方法中也会使用GenericObjectPool] 时,会生成一个内嵌类Evictor,实现自Runnable接口。如果timeBetweenEvictionRunsMillis大于0,每过timeBetweenEvictionRunsMillis毫秒Evictor会调用evict()方法,检查对象的闲置时间是否大于 minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小于等于0时则忽略,默认为30分钟),是则销毁此对象,否则就激活并校验对象,然后调用ensureMinIdle方法检查确保池中对象个数不小于_minIdle。在调用returnObject方法把对象放回对象池,首先检查该对象是否有效,然后调用PoolableObjectFactory 的passivateObject方法使对象处于非活动状态。再检查对象池中对象个数是否小于maxIdle,是则可以把此对象放回对象池,否则销毁此对象
上述特性的可设置性已在代码中验证,具体性能是否能实现有待实际验证

2. C3P0

C3P0的官方example中使用的数据源为ComboPooledDataSource,网上一篇文章详细介绍了C3P0连接池配置中各项含义[这些配置项的含义在下载解压c3p0的压缩包之后目录的doc\index.html中的Configuration部分也有详细的介绍,这里偷下懒:P],现摘录如下:
<c3p0-config>
<default-config>


<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">3</property>


<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">30</property>


<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>


<!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
<property name="autoCommitOnClose">false</property>


<!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么
属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试
使用。Default: null-->
<property name="automaticTestTable">Test</property>

<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">false</property>


<!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
<property name="checkoutTimeout">100</property>


<!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name="connectionTesterClassName"></property>

<!--指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
Default: null-->
<property name="factoryClassLocation">null</property>

<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文档原文)作者强烈建议不使用的一个属性-->
<property name="forceIgnoreUnresolvedTransactions">false</property>

<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>

<!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize">3</property>

<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">60</property>

<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">15</property>

<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">100</property>

<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
<property name="maxStatementsPerConnection"></property>

<!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能
通过多线程实现多个操作同时被执行。Default: 3-->
<property name="numHelperThreads">3</property>

<!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0
的数据源时。Default: null-->
<property name="overrideDefaultUser">root</property>

<!--与overrideDefaultUser参数对应使用的一个参数。Default: null-->
<property name="overrideDefaultPassword">password</property>

<!--密码。Default: null-->
<property name="password"></property>

<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:
测试的表必须在初始数据源的时候就存在。Default: null-->
<property name="preferredTestQuery">select id from test where id=1</property>

<!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">300</property>

<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">false</property>

<!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->
<property name="testConnectionOnCheckin">true</property>

<!--用户名。Default: null-->
<property name="user">root</property>

<!--早期的c3p0版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数
允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始
广泛的被使用,所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到
支持,但今后可能的版本可能不支持动态反射代理。Default: false-->
<property name="usesTraditionalReflectiveProxies">false</property>


<property name="automaticTestTable">con_test</property>
    <property name="checkoutTimeout">30000</property>
    <property name="idleConnectionTestPeriod">30</property>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">25</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">0</property>
    <user-overrides user="swaldman">
    </user-overrides>
</default-config>
<named-config name="dumbTestConfig">
    <property name="maxStatements">200</property>
    <user-overrides user="poop">
      <property name="maxStatements">300</property>
    </user-overrides>
   </named-config>
</c3p0-config>
上述特性的可设置性已在代码中验证,具体性能是否能实现有待实际验证
从配置项的内容来看,C3P0和DBCP都有比较详细的有关连接检测保证的配置,我们可以看到C3P0可以控制数据源内加载的PreparedStatements数量,并且可以设置帮助线程的数量来提升JDBC操作的速度,这些是DBCP未提供的;另外从网络上的评价来看,DBCP出现Bug的频率要大于C3P0,不过这一点有待于我们自己实际的检测。

3. Proxool

Proxool的使用和dbcp以及c3p0稍有不同,我们需要并且只需要在使用基本的java.sql.DriverManager之前加载org.logicalcobwebs.proxool.ProxoolDriver驱动类,并且按照proxool定义的url格式 ["proxool." + alias + ":" + driverClass + ":" + driverUrl ,其中alias是为连接池自定义的别名] 来获得connection;具体的可以参看proxool doc下的UserGuide,或本文所附的示例代码。下面对连接池的特性配置作详细说明 [这个是自己翻译的,不一定准确,有问题时请参看doc下的Properties ~]。

fatal-sql-exception

以逗号隔开的异常列表,当设置了此项之后,每当出现SQLException时都将与列表中异常项作比较,如果匹配则认为出现fatal异常,这将导致connection被丢弃,并且不论出现任何情况该异常将被重抛一次以通知用户发生的情况。默认值为null

fatal-sql-exception-wrapper-class

如果配置了fatal-sql-exception,则默认的操作是丢 弃引起SQLException的原因而只是抛出原始异常。使用fatal-sql-exception-wrapper-class这个特性可以将 SQLException包装到继承SQLException或RunTimeException的任何异常类里。Proxool提供了两个类供使用 FatalSQLException和FatalRunTimeException;使用这两个类的话就将该选项设置为 'org.logicalcobwebs.proxool.FatalSQLException'或者 'org.logicalcobwebs.proxool.FatalRuntimeException'。默认值为null

house-keeping-sleep-time

proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁,默认值为30秒

house-keeping-test-sql

如果侦察线程发现闲置连接,则会使用这个SQL语句来对这些连接进行检查;这项设置的语句应该能够被很快的执行,例如查询当前时间 [info.setProperty("proxool.house-keeping-test-sql", "select CURRENT_DATE");] 。如果不设置则该选项被忽略

injectable-connection-interface、injectable-statement-interface、injectable-prepared-statement-interface、injectable-callable-statement-interface

jmx

如果此项设为true,则连接池将被以名称"Proxool:type=Pool, name=<alias>"注册为JMS Server的MBean。默认值为false

jmx-agent-id

当且仅当jmx选项设为true时使用,为以逗号分隔的连接持注册到的JMS代理名称列表;如果不设置则所有注册的JMX Server都将被使用

maximum-active-time

线程最大存活时间,超过此时间的线程将被守护线程kill掉,默认值为5分钟

maximum-connection-count

到数据库的最大连接数,超过了这个连接,再有请求时,就排在队列中等候,最大的等待请求数由simultaneous-build-throttle决定;默认值为15

maximum-connection-lifetime

连接最大存活时间,毫秒为单位,默认值为4小时

minimum-connection-count

不管是否被使用都保持开放的最小连接数,默认值为5

overload-without-refusal-lifetime

用来判断连接池状态,如果在此选项设置时间内(毫秒为单位)拒绝了连接,则认为过负载。默认值为60秒

prototype-count

最少保持的空闲连接数,注意与minimum-connection-count区分。默认值为0

simultaneous-build-throttle

最大的等待请求数,默认值为10

test-before-use

如果设为true则connection在使用前将以house-keeping-test-sql设置的语句测试,如果测试不通过则该connection被丢弃并会重新分配一个connection。默认为false

test-after-use

如果设为true则connection在关闭(放回连接池)前将以house-keeping-test-sql设置的语句测试,如果测试不通过connection将被丢弃。默认值为false

与其它连接池特性的设置方法不同,Proxool不提供相应的set方法,所有特性都要以诸如info.setProperty("proxool.jmx", "false");方式设定

上述特性的可设置性已在代码中验证,具体性能是否能实现有待实际验证


引自原网址:http://fengbin2005.iteye.com/blog/1906488

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值