在用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