1. 程式人生 > >mysql重連,連線丟失:The last packet successfully received from the server

mysql重連,連線丟失:The last packet successfully received from the server

問題原因:

其實上面的提示中已經給出了一部分的簡要說明,簡單來說就是: 程式啟動時,在跟DB首次互動時,獲得了相應的DB Connection資源,從而進行正常的DB讀寫操作。但是在下次進行DB讀寫時(我的定時任務本身設定的時間間隔是24小時),應用程式認為這個連線是可以正常使用的(程式執行過一次之後沒有退出,這個連線從來並沒有被釋放掉),但實際上,這個連線已經壞掉了,因為Mysql本身已經把這個連線標記為timeout了。於是,應用程式“傻乎乎”的在這個已經壞掉的資料通道上發起對DB的讀寫請求,但是Mysql已經對這些請求不買賬了。。。

為啥呀,mysql到底認為這個連線空閒多長時間算過期啊?

這個可以通過檢視mysql的配置檔案,看看是否有對這個時間做過特殊的配置,我的場景下在64位linux伺服器上部署的mysql伺服器,這個配置檔案在:在/etc/my.cnf

如果你開啟這個檔案,發現並沒有如下這行配置:

Xml程式碼  收藏程式碼
  1. wait_timeout=xxx (這裡xxx是資料,單位為秒)  

說明你並沒有對這個timeout做過特殊配置,通常Mysql預設的配置是8小時。你也可以在登陸進入mysql之後,通過如下命令確認一下:

Sql程式碼  收藏程式碼
  1. show global variables like 'wait_timeout';  

結合上面我的程式的配置(24小時執行一次),上面的問題就好解釋了:24小時之後程式再次對DB進行讀寫操作時,Mysql單方已經認為之前connection已經timeout了(停止活動了8小時以上就認為過期了)。

如何解決:


1.1 錯誤資訊:

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 20,820,001 milliseconds ago.  The last packet sent successfully to the server was 20,820,002 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.GeneratedConstructorAccessor29.newInstance(Unknown Source) ~[na:na]
		at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.7.0_51]
		at java.lang.reflect.Constructor.newInstance(Constructor.java:526) ~[na:1.7.0_51]
		at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1129) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3988) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2598) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2828) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:5372) ~[mysql-connector-java-5.1.29.jar:na]
		at com.mchange.v2.c3p0.impl.NewProxyConnection.setAutoCommit(NewProxyConnection.java:881) ~[c3p0-0.9.1.1.jar:0.9.1.1]
		at org.quartz.impl.jdbcjobstore.AttributeRestoringConnectionInvocationHandler.setAutoCommit(AttributeRestoringConnectionInvocationHandler.java:98) ~[quartz-2.2.1.jar:na]

1.2 解決方法

- 如果使用的是JDBC,在JDBC URL上新增?autoReconnect=true,如:

jdbc:mysql://10.10.10.10:3306/mydb?autoReconnect=true

- 如果是在Spring中使用DBCP連線池,在定義datasource增加屬性validationQuerytestOnBorrow,如:

<bean id="vrsRankDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${countNew.jdbc.url}" />
    <property name="username" value="${countNew.jdbc.user}" />
    <property name="password" value="${countNew.jdbc.pwd}" />
    <property name="validationQuery" value="SELECT 1" />
    <property name="testOnBorrow" value="true"/>
</bean>

- 如果是在Spring中使用c3p0連線池,則在定義datasource的時候,新增屬性testConnectionOnCheckintestConnectionOnCheckout,如:

<bean name="cacheCloudDB" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driver}"/>
    <property name="jdbcUrl" value="${cache.url}"/>
    <property name="user" value="${cache.user}"/>
    <property name="password" value="${cache.password}"/>
    <property name="initialPoolSize" value="10"/>
    <property name="maxPoolSize" value="${cache.maxPoolSize}"/>
    <property name="testConnectionOnCheckin" value="false"/>
    <property name="testConnectionOnCheckout" value="true"/>
    <property name="preferredTestQuery" value="SELECT 1"/>
</bean>