Mybatis破MySql8小時斷線問題

MySql有一個系統變量,如圖:java

以上數值,單位爲秒。mysql

mysql的鏈接容許的閒置時間。當超過閒置時間之後,database端就會將此鏈接單方面廢棄。這時若是使用jdbc繼續使用以前的鏈接,則會收到如下異常:web

### Cause: java.sql.SQLException: Could not retrieve transation read-only status server
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:111)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:119)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
	at com.sun.proxy.$Proxy8.getMonthlyChart(Unknown Source)
	at com.lux.rcc.kpi.bo.ChartABo.getMonthlyChart(ChartABo.java:46)
	at com.lux.rcc.kpi.servlets.ChatAServlet.doGet(ChatAServlet.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:722)
Caused by: java.sql.SQLException: Could not retrieve transation read-only status server
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1086)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:975)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:920)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:951)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:941)
	at com.mysql.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:3972)
	at com.mysql.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:3943)
	at com.mysql.jdbc.PreparedStatement.checkReadOnlySafeStatement(PreparedStatement.java:1258)
	at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1278)
	at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:62)
	at com.sun.proxy.$Proxy10.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:59)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:73)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:60)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108)
	... 28 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 85,659,759 milliseconds ago.  The last packet sent successfully to the server was 85,659,775 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.
	at sun.reflect.GeneratedConstructorAccessor24.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
	at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1129)
	at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3988)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2598)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2828)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2777)
	at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1651)
	at com.mysql.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:3966)
	... 44 more
Caused by: java.net.SocketException: Software caused connection abort: socket write error
	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
	at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
	at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
	at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3969)
	... 50 more

mysql容許設置閒置時間,默認是8小時,最大是1年。sql

大部分客戶端都使用鏈接池以提升性能,若是用戶訪問量不大,鏈接池中的鏈接可能閒置時間超過數據庫容許時間,數據庫單方面斷掉鏈接,而客戶端殊不知情。當下一個用戶訪問時,使用鏈接池中的鏈接,則會拋出上述異常。數據庫

解決方法能夠是增大閒置時間。但這不是一個好方法。閒置時間是有上限的,在極端狀況下,仍是可能發生異常。此外,長時間保留閒置的鏈接,會下降數據庫性能,消耗內存,最終耗盡數據庫的鏈接數。因此不推薦增大閒置時間。apache

通常經常使用的解決方法是在使用一個長時間閒置的鏈接以前,對它ping一下,確保它還在正常工做。在mybatis自帶鏈接池配置中,是這樣作的:tomcat

        <environment id="development">
            <transactionManager type="jdbc" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/kpi?autoReconnect=true" />
                <property name="username" value="mysql" />
                <property name="password" value="mysql" />
                <property name="poolPingEnabled" value="true"/>
                <property name="poolPingQuery" value="select now() from kpi.lastupdatedlog limit 1"/>
                <property name="poolPingConnectionsNotUsedFor" value="3600000"/>
            </dataSource>
        </environment>

配置鏈接池時,須要聲明三個屬性:websocket

  1. poolPingEnabled - 默認值是false,當值爲true的時候,將開啓ping機制。session

  2. poolPingQuery - 對數據庫進行ping時所使用的sql。mybatis

  3. poolPingConnectionsNotUsedFor - 默認值是0,單位是毫秒。咱們不能在每次使用鏈接池以前,都使用ping機制,這會使每一條sql的執行,都要額外執行一次ping語句。因此使用此屬性來避免這種不合理作法。咱們只針對閒置時間超過某個時間的鏈接,進行ping。本例中的值爲1小時,當從鏈接池中拿出的鏈接閒置超過1小時,纔會對它進行ping。

相關文章
相關標籤/搜索