在用MySQL客戶端對數據庫進行操做時,若是一段時間沒有操做,再次操做時,經常會報以下錯誤:html
ERROR 2013 (HY000): Lost connection to MySQL server during query
ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect...
這個報錯信息就意味着當前的鏈接已經斷開,須要從新創建鏈接。mysql
那麼,鏈接創建後,鏈接的時長是如何肯定的呢?git
在MySQL中,這個與兩個參數interactive_timeout
和wait_timeout
的設置有關。github
注:如下說明基於MySQL 5.7.sql
1.interactive_timeout和wait_timeout的定義
首先,看看官方文檔對於這兩個參數的定義。數據庫
interactive_timeoutsession
The number of seconds the server waits for activity on an interactive connection before closing it. An interactive client is defined as a client that uses the CLIENT_INTERACTIVE option to mysql_real_connect(). See also wait_timeout.
interactive_timeout參數,定義了對於交互式鏈接,服務端等待數據的最大時間。若是超過這個時間,服務端仍然沒有收到數據,則會關閉鏈接。tcp
所謂交互式client,是指調用mysql_real_connect()函數創建鏈接時,設置了CLIENT_INTERACTIVE選項。比較經常使用的就是命令行終端。函數
查看interactive_timeout的值:測試
mysql> show global variables like 'interactive_timeout%'; +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | +---------------------+-------+ 1 row in set (0.01 sec)
默認是28800,單位秒,即8個小時
wait_timeout
The number of seconds the server waits for activity on a noninteractive connection before closing it. On thread startup, the session wait_timeout value is initialized from the global wait_timeout value or from the global interactive_timeout value, depending on the type of client (as defined by the CLIENT_INTERACTIVE connect option to mysql_real_connect()). See also interactive_timeout.
wait_timeout參數,定義對於非交互式鏈接,服務端等待數據的最長時間。若是超過這個時間,服務端仍然沒有收到數據,則會關閉鏈接。
在鏈接線程啓動的時候,根據鏈接的類型,決定會話級的wait_timeout的值是初始化爲全局的wait_timeout,仍是全局的interactive_timeout。即若是是交互式鏈接,會話變量wait_timeout初始化爲全局的interactive_timeout,不然,初始化爲全局的wait_timeout。
查看wait_timeout的值:
mysql> show global variables like 'wait_timeout%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | wait_timeout | 28800 | +---------------+-------+ 1 row in set (0.00 sec)
默認一樣是28800s,即8小時。
根據上述定義,二者的區別顯而易見:interactive_timeout針對交互式鏈接,wait_timeout針對非交互式鏈接。所謂的交互式鏈接,即在mysql_real_connect()函數中使用了CLIENT_INTERACTIVE選項。
說得直白一點,經過mysql命令行終端鏈接數據庫是交互式鏈接,經過jdbc等鏈接數據庫是非交互式鏈接。
下面來測試一下,確認以下問題:
- 控制鏈接最大空閒時長的是哪一個參數。
- 會話變量wait_timeout的繼承問題
2.控制鏈接最大空閒時長的是哪一個參數
先給出答案:wait_timeout
接下來進行驗證。
2.1 只修改會話的wait_timeout參數
查看當前會話的wait_timeout和interactive_timeout。
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
設置當前會話的wait_timeout爲10s
mysql> set session wait_timeout=10; Query OK, 0 rows affected (0.00 sec)
再次查看
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 10 | +---------------------+-------+ 2 rows in set (0.00 sec)
等待10s,再次查看
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 8 Current database: *** NONE *** +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.01 sec)
能夠看到,等待10s後再執行操做,原來的鏈接已經斷開,並從新創建鏈接。
2.2 只修改會話的interactive_timeout參數
首先查看當前會話的interactive_timeout和wait_timeout.
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
接着,設置當前會話的interactive_timeout爲10s
mysql> set session interactive_timeout=10; Query OK, 0 rows affected (0.00 sec)
再次查看
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 10 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.01 sec)
等待10s,再次查看
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 10 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
能夠看到,即便等待10後,鏈接是正常的。因此,設置interactive_timeout,對鏈接的時長沒有影響。
3.會話變量wait_timeout的繼承問題
上面已經提到,若是是交互式鏈接,則繼承自全局變量interactive_timeout的值,若是是非交互式鏈接,則繼承自全局變量wait_timeout的值。
下面進行驗證。
3.1 只修改全局變量interactive_timeout的值
首先查看全局的interactive_timeout和wait_timeout。
mysql> show global variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
接着,設置全局的interactive_timeout爲10s。
mysql> set global INTERACTIVE_TIMEOUT=10; Query OK, 0 rows affected (0.00 sec)
再次查看
mysql> show global variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 10 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
開啓另一個MySQL客戶端,查看會話變量的值:
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 10 | | wait_timeout | 10 | +---------------------+-------+ 2 rows in set (0.01 sec)
發現,WAIT_TIMEOUT的值已經變爲10了。
等待10s後,再次查看,會發現原來的鏈接已經斷開,鏈接的時長設置已經生效。
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 70 Current database: *** NONE *** +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 10 | | wait_timeout | 10 | +---------------------+-------+ 2 rows in set (0.01 sec)
但經過非終端測試,wait_timeout的值依舊是28800:
package main import ( "database/sql" "log" _ "github.com/go-sql-driver/mysql" ) var DB *sql.DB var dataBase = "root:Aa123456@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true" func mysqlInit() { var err error DB, err = sql.Open("mysql", dataBase) if err != nil { log.Fatalln("open db fail:", err) } DB.SetMaxOpenConns(1) err = DB.Ping() if err != nil { log.Fatalln("ping db fail:", err) } } func main() { mysqlInit() execSql() } func execSql() { var variableName string var value int sql := "show session variables where Variable_name in ('interactive_timeout', 'wait_timeout')" rows, err := DB.Query(sql) if err != nil { log.Println("query failed:", err) return } defer rows.Close() for rows.Next() { err = rows.Scan(&variableName, &value) if err != nil { log.Println("rows.Scan failed:", err) return } log.Println("variable_name:", variableName, ", value:", value) } }
output:
2019/10/13 17:11:22 variable_name: interactive_timeout , value: 10 2019/10/13 17:11:22 variable_name: wait_timeout , value: 28800
結果輸出以下
INTERACTIVE_TIMEOUT: 10 WAIT_TIMEOUT: 28800
3.2 只修改全局變量wait_timeout的值
首先查看全局的interactive_timeout和wait_timeout。
mysql> show global variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
接着,將全局的WAIT_TIMEOUT設置爲20s。
mysql> set global WAIT_TIMEOUT=20; Query OK, 0 rows affected (0.07 sec)
再次查看
mysql> show global variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 20 | +---------------------+-------+ 2 rows in set (0.00 sec)
開啓另一個mysql客戶端,查看會話變量的值
mysql> show session variables where Variable_name in ('interactive_timeout', 'wait_timeout'); +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | | wait_timeout | 28800 | +---------------------+-------+ 2 rows in set (0.00 sec)
WAIT_TIMEOUT的值依舊是28800.
查看非終端的代碼執行的結果:
func execSql() { var variableName string var value int sql := "show session variables where Variable_name in ('interactive_timeout', 'wait_timeout')" rows, err := DB.Query(sql) if err != nil { log.Println("query failed:", err) return } defer rows.Close() for rows.Next() { err = rows.Scan(&variableName, &value) if err != nil { log.Println("rows.Scan failed:", err) return } log.Println("variable_name:", variableName, ", value:", value) } }
output:
2019/10/13 17:23:10 variable_name: interactive_timeout , value: 28800 2019/10/13 17:23:10 variable_name: wait_timeout , value: 20
修改程序,執行sql語句後,等待25s後,再次執行sql語句,查看執行狀況。
func main() { mysqlInit() for { execSql() time.Sleep(25*time.Second) } } func execSql() { var variableName string var value int sql := "show session variables where Variable_name in ('interactive_timeout', 'wait_timeout')" rows, err := DB.Query(sql) if err != nil { log.Println("query failed:", err) return } defer rows.Close() for rows.Next() { err = rows.Scan(&variableName, &value) if err != nil { log.Println("rows.Scan failed:", err) return } log.Println("variable_name:", variableName, ", value:", value) } }
output:
2019/10/13 17:26:46 variable_name: interactive_timeout , value: 28800 2019/10/13 17:26:46 variable_name: wait_timeout , value: 20 [mysql] 2019/10/13 17:27:11 packets.go:36: unexpected EOF [mysql] 2019/10/13 17:27:11 packets.go:141: write tcp 127.0.0.1:53878->127.0.0.1:3306: write: broken pipe 2019/10/13 17:27:11 variable_name: interactive_timeout , value: 28800 2019/10/13 17:27:11 variable_name: wait_timeout , value: 20
能夠看到,等待25s後,再次執行sql,此時鏈接已經斷開。 底層又從新創建鏈接。
4.總結
-
控制鏈接最大空閒時長的wait_timeout參數。
-
關於wait_timeout的繼承
- 對於非交互式鏈接,相似於jdbc鏈接,wait_timeout的值繼承自全局變量wait_timeout。
- 對於交互式鏈接,相似於mysql命令行終端,wait_timeout的值繼承全局變量interactive_timeout。
-
判斷一個鏈接的空閒時間,可經過show processlist輸出中Sleep狀態的時間
mysql> show processlist; +----+------+----------------------+------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+----------------------+------+---------+------+-------+------------------+ | 2 | root | localhost | NULL | Query | 0 | init | show processlist | | 6 | repl | 192.132.2.66:56001 | NULL | Sleep | 1201 | | NULL | +----+------+----------------------+------+---------+------+-------+------------------+ 2 rows in set (0.03 sec)
5.參考
https://www.cnblogs.com/ivictor/p/5979731.html
http://www.cnblogs.com/cenalulu/archive/2012/06/20/2554863.html