1. 程式人生 > 其它 >如果你的專案重啟資料庫連線數突增!連線資料庫超時!請收下這個方子

如果你的專案重啟資料庫連線數突增!連線資料庫超時!請收下這個方子

技術標籤:Mybatismybatisjava面試jdbc資料庫

結論:

資料庫連線數突增是資料庫連線資源沒有及時釋放。

連線資料庫超時是因為資料庫連線資源釋放的過早。

現象1:每次上線專案DB的連線數會突增。

原因:是專案關閉的時候沒有釋放連線資源導致。

DB的connection資源沒有正常釋放,導致專案啟動的時候再次建立資料庫連線資源,就出現了連線數突增的現象。一段時間後mysql根據wait_time的配置,自動回收conncetion,所以連線數又回落回來。

如果是是DB的connection資源沒有正常釋放,最可能的是在專案關閉的時候沒有釋放掉DB的連線資源。

經過在檢視線上jekins的上線指令碼後,發現線上停止專案使用的kill程序的方式來停止專案。那麼就證明假設都成立了。接下來解決問題環節(程式設計師們喜聞樂見的百度和谷歌環節了)。

如何釋放DB的連線資源,我列舉了一下可選方案。

1.主動釋放

專案關閉使用正確的stop命令,保證專案能正確的釋放掉各種資源。
執行命令:xxxx_tomcat.stop

2.被動釋放

如下兩個配置搭配服用效果最佳
1.JDBC探活:每隔一段時間喚醒連線,保持長連線。
<property name="preferredTestQuery" value="SELECT 1"/> 
<property name="idleConnectionTestPeriod" value="300"/>
2.減少連線池內連線生存週期:
  2.1 使之小於mysql設定中的wait_timeout的值
  2.2 大於配置的探活的週期
  2.3 小於新專案上線的耗時,就可以在新專案上線過程中mysql自己回收連線資源避免連線突增的現象的發生。
<property name="maxIdleTime" value="1800" />

主要目的是儘可能的在新專案上線的同時,mysql自己就回收了連線資源。

現象2:連線資料庫超時。

com.mysql.jdbc.CommunicationsException: 
The last packet successfully received from the server was58129 seconds ago.
The last packet sent successfully to the server was 58129 seconds ago, 
which 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. mysql

問題原因 :連線池裡的connection資源mysql主動提前釋放導致。

原因是在datasource連線池中配置的最大空閒時間到達之前(比如maxIdleTime,不通資料來源配置名不一樣),已經到達mysql的wait_timeout(最大空閒時間),是mysql主動把connection資源回收。但是專案中的連線池還持有connection,所以當專案中使用connection的時候會報CommunicationsException錯誤。

解決方案

1.修改mysql的wait_time,interactive_timeout把值調大(不建議如果太大,可能導致連線數較多,引起效能下降)

修改配置my.inf檔案 
或者 
mysql命令set global interactive_timeout = 28800;set global interactive_timeout = 28800;

2.配置JDBC的重連機制autoReconnect(不建議,只有4.x版本,起作用)

jdbc:mysql://localhost:3306/test?user=root&password=&autoReconnect=true

3.減少連線池內的存活時間+JDBC探活(建議,搭配使用效果好)

JDBC探活:每隔一段時間喚醒連線,從而保持長連線
<property name="preferredTestQuery" value="SELECT 1"/> 
<property name="idleConnectionTestPeriod" value="300"/>

JDBC減少連線池內連線生存週期,**小於mysql配置wait_timeout 的值(很重要)***
<property name="maxIdleTime" value="1800" />   

最大閒置資源時間的配置

兩個現象的解決方案都指向了同一個配置就是connection的最大閒置資源時間。

有兩個地方可以配置最大閒置資源時間:

1.在專案的連線池中配置,比如maxIdleTime。

2.在mysql中也可以配置,interactive_timeout和wait_timeout。

三、MySql中的connection超時配置

mysql的配置中有interactive_timeout和wait_timeout兩個引數,這兩個引數有時候還存在覆蓋的關係,所以還是給大夥說清楚一點兩個的區別和聯絡方便大家理解。

建議interactive_timeout和wait_timeout引數值配置成一樣的。

1.interactive_timeout和wait_timeout概念

mysql的連線超時時間配置
wait_timeout非互動式連線超時通過jdbc連線資料庫是非互動式連線,最大閒置時間用於規定一個connection最大的空閒時間,預設是28800秒,超時MySQL會自動回收該connection。
interactive_timeout互動式連線超時通過mysql客戶端連線資料庫是互動式連線,最大閒置時間用於規定一個connection最大的空閒時間,預設是28800秒,超時MySQL會自動回收該connection。

2.修改配置引數的方式

1.修改配置檔案my.ini

[mysqld]
wait_timeout = 20
interactive_timeout = 20

2.執行mysql命令

#修改global級別的配置
set global interactive_timeout = 10;
set global wait_timeout = 10;
#修改session級別的配置
set session interactive_timeout=20;
set session wait_timeout=20;

3.檢視引數配置

mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| have_statement_timeout      | YES      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 28800    |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 60       |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 60       |
| wait_timeout                | 28800    |
+-----------------------------+----------+
13 rows in set (0.00 sec)

3.引數不同的繼承關係

1.interactive_timeout和wait_timeout配置最終生效都是作用在session互動的時候生效。

2.控制最大空閒時間的引數是wait_timeout在起作用。不管是非互動式還是互動式連線,都是wait_timeout起作用

3.互動式連線下的wait_timeout和interactive_timeout配置都會繼承自全域性的interactive_timeout引數。

總結規律
非互動,比如jdbc連線互動式,比如mysql客戶端
global級別查詢session級別的配置查詢session級別的配置
wait_timeout=26繼承值wait_timeout=26
interactive_timeout=31繼承值interactive_timeout=31wait_timeout=31,interactive_timeout=31

1.wait_timeout決定連線超時時間的演示

因為我們是用mysql客戶端連線,應該是互動式連線,連線超時起作用的應該是interactive_timeout引數,但是真是的這樣嗎。

確認設定連線空閒超時時間是WAIT_TIMEOUT

============= wait_timeout ================
mysql> set session WAIT_TIMEOUT=2;
Query OK, 0 rows affected (0.00 sec)
等待2秒再次查詢,連線已經丟失,說明配置生效。
mysql> select 1;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    50
Current database: *** NONE ***

+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

============= interactive_timeout ================

mysql> set session  interactive_timeout=2;
Query OK, 0 rows affected (0.00 sec)
等待2秒再次查詢,連線也沒有丟失,說明配置未生效。
mysql> select 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

2.interactive_timeout不同的繼承演示

設定interactive_timeout的配置
mysql> set global interactive_timeout=10;
Query OK, 0 rows affected (0.00 sec)

mysql> select variable_name,variable_value from information_schema.global_variables where variable_name in ('interactive_timeout','wait_timeout');
+---------------------+----------------+
| variable_name       | variable_value |
+---------------------+----------------+
| INTERACTIVE_TIMEOUT | 10             |
| WAIT_TIMEOUT        | 28800          |
+---------------------+----------------+
2 rows in set, 1 warning (0.00 sec)

新開一個視窗(互動式連線)檢視,wait_timeout和interactive_timeout 都繼承自global的interactive_timeout

互動式連線下可以看到interactive_timeout和wait_timeout都繼承自全域性INTERACTIVE_TIMEOUT
mysql> select variable_name,variable_value from information_schema.session_variables where variable_name in ('interactive_timeout','wait_timeout');
+---------------------+----------------+
| variable_name       | variable_value |
+---------------------+----------------+
| INTERACTIVE_TIMEOUT | 10             |
| WAIT_TIMEOUT        | 10             |
+---------------------+----------------+
2 rows in set, 1 warning (0.00 sec)

使用JDBC查詢(非互動式)檢視,wait_timeout繼承自全域性wait_timeout,interactive_timeout繼承自全域性interactive_timeout

Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/deeluma_01", "root", "root");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select variable_name,variable_value from information_schema.session_variables where variable_name in ('interactive_timeout','wait_timeout')");
while(resultSet.next()){
	String variable_name = resultSet.getString("variable_name");
	int variable_value = resultSet.getInt("variable_value");
	System.out.println(variable_name+":"+variable_value);
}

//非互動式下檢視,wait_timeout繼承自全域性wait_timeout,interactive_timeout繼承自全域性interactive_timeout
//===============//
INTERACTIVE_TIMEOUT:10
WAIT_TIMEOUT:28800