1. 程式人生 > >資料庫連結超時(預設8小時)報錯:MySQLNonTransientConnectionException

資料庫連結超時(預設8小時)報錯:MySQLNonTransientConnectionException

異常資訊

?
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 integertimeBetweenEvictionRunsMillis = 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 staleidleConnectionTestPeriod = 18000

//set to something slightly less than wait_timeout, preventing 'stale' connections from being handed outmaxIdleTime = 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 -->
<!-- 資料來源 --> 
<beanid="dataSourceTarget"class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<propertyname="user"value="root" />
<propertyname="password"value="root" />
<propertyname="jdbcUrl"value="jdbc:mysql://192.168.61.208:3306/sinoomv1_0_0" />
<propertyname="driverClass"value="com.mysql.jdbc.Driver" />
<!-- 系統初始化連線數 -->
<propertyname="initialPoolSize"value="10" />
<!-- 最大連線數 -->
<propertyname="maxPoolSize"value="30" />
<!-- 最小連線數 -->
<propertyname="minPoolSize"value="10" />
<!--最大空閒時間,600秒(10分鐘)內未使用則連線被丟棄。若為0則永不丟棄。Default: 0 -->
<propertyname="maxIdleTime"value="600" />
<!--當連線池中的連線耗盡的時候c3p0一次同時獲取的連線數。Default: 3 -->  
<propertyname="acquireIncrement"value="3" />
<!--每60秒檢查所有連線池中的空閒連線。Default: 0 -->  
<propertyname="idleConnectionTestPeriod"value="60" />
<!-- 每次從pool內checkout連線時測試有效性(同步操作)
    程式每次資料庫呼叫都連線有效性,若無效關閉此連線並剔除出pool,
   從pool內取其他連線,慎用,會造成至少多一倍的資料庫呼叫。Default:false -->
<propertyname="testConnectionOnCheckout"value="false" />
<!--定義在從資料庫獲取新連線失敗後重復嘗試的次數。Default: 30 -->
<propertyname="acquireRetryAttempts"value="30"/>
<!--兩次連線中間隔時間,單位毫秒。Default: 1000 -->
<propertyname=