資料庫連結超時(預設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)
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種:
- 增加 wait_timeout 的時間。
- 減少 Connection pools 中 connection 的 lifetime。
- 測試 Connection pools 中 connection 的有效性。
- 自己最終解決:將原來的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=