問題:
mysql 8小時斷開連接問題:mysql的默認設置下,當一個連接的空閑時間超過8小時后,mysql 就會斷開該連接,而連接池認為連接依然有效。在這種情況下,如果客戶端代碼向連接池請求連接的話,連接池就會把已經失效的連接返回給客戶端,客戶端在使用該失效連接的時候即拋出異常。
解決方案:
可以通過數據庫連接池的配置來解決此問題。下面通過例子進行說明為了便於模擬,首先將數據庫的最大超時時間改為10s,也就是說10s空閑后就會超時斷開,如下:
使用dbcp的連接池(使用其他的如c3p0、druid連接池情況類似)。
配置一:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="testOnBorrow" value="true"/> //默認值
public class Main { public static void main(String[] args) throws BeansException, Exception { ApplicationContext context = new ClassPathXmlApplicationContext("spring-context*.xml"); //測試mybatis System.out.println(context.getBean(TestDao.class).getAll()); Thread.sleep(15000); System.out.println(context.getBean(TestDao.class).getAll()); } }
執行測試方法,間隔15s執行的兩次查詢都執行成功。
分析:
<property name="testOnBorrow" value="true"/>,此處為了更清楚地說明testOnBorrow的效果,特別顯式的進行了配置,其實dbcp對testOnBorrow默認的配置就是true。
這個配置的意思是每次取一個連接的時候都要進行測試,這樣就能避免出現異常的情況。
配置二:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="testOnBorrow" value="false"/>
將testOnBorrow設置為false,每次取出連接時不進行判斷,測試結果,報錯:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure。
將testOnBorrow設置為true或者使用默認配置能解決mysql 8小時問題,但每次取連接都進行一次測試的方式在請求量特別大的情況下性能是不佳的,於是出現了下面的方案。
配置三:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="testOnBorrow" value="false"/> <property name="validationQuery" value="select 1"/> <property name="testWhileIdle" value="true"/> <property name="timeBetweenEvictionRunsMillis" value="5000"/>
執行測試方法,間隔15s執行的兩次查詢都執行成功。
分析:
testWhileIdle設置為true,即空閑時對連接進行測試,timeBetweenEvictionRunsMillis即空閑5000ms進行一次測試,validationQuery即進行測試時執行的語句。所以只要
timeBetweenEvictionRunsMillis時間間隔小於數據庫設置的超時時間間隔(5s<10s),就能避免8小時斷開連接問題。實際環境中根據數據庫配置的超時時間,配置相應的
timeBetweenEvictionRunsMillis即可。比如數據庫8小時斷開連接,我們配置timeBetweenEvictionRunsMillis為1小時。