在用MySQL客户端对数据库进行操作时,如果一段时间没有操作,再次操作时,常常会报如下错误:

ERROR 2013 (HY000): Lost connection to MySQL server during query
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...

这个报错信息就意味着当前的连接已经断开,需要重新建立连接。

那么,连接建立后,连接的时长是如何确定的呢?

在MySQL中,这个与两个参数interactive_timeoutwait_timeout的设置有关。

注:以下说明基于MySQL 5.7.

1.interactive_timeout和wait_timeout的定义

首先,看看官方文档对于这两个参数的定义。

interactive_timeout

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参数,定义了对于交互式连接,服务端等待数据的最大时间。如果超过这个时间,服务端仍然没有收到数据,则会关闭连接。

所谓交互式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

http://www.cnblogs.com/Alight/p/4118515.html

http://ronaldbradford.com/blog/sqlstatehy000-general-error-2006-mysql-server-has-gone-away-2013-01-02/

MySQL 的连接时长控制--interactive_timeout和wait_timeout的更多相关文章

  1. MySQL左连接时 返回的记录条数 比 左边表 数量多

    在学MySQL的连接时,为了便于记忆,就将左连接 记做 最后结果的总记录数 和 进行左连接的左表的记录数相同,简单的说就是下面这个公式 count(table A left join table B) ...

  2. MySQL 8 连接时出现 1251 和 2059 错误

    MySQL 8 连接时出现 1251 和 2059 错误 原因是MySQL 8 改了密码加密算法.1 原来是:mysql_native_password MySQL8 改成了 caching_sha2 ...

  3. 修改MYSQL的默认连接时长

    show global variables like 'wait_timeout'; 设置成10小时; set global wait_timeout=36000;

  4. JAVA Socket 连接时长

    其实关于这个问题可能用到的人不会很多,不过我在这里还是说说. 正常很多人写socket通信时,都会直接通过new socket(IP,PORT)直接去链接服务器.其实这种做法也没有错误,但是若当服务器 ...

  5. MySQL JOIN 连接时,条件为以逗号分隔的字段与 ID 相匹配

    一.背景 有一张相片表,一张相片所属标签表,一张相片可以归属于多个标签,表结构如下: 现在需要通过一次查询,得到每一张照片对应的标签名称,标签名称之间以固定的分隔符连接,结果如下图: 二.查询语句 原 ...

  6. mysql jdbc连接时的小问题java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)

    这次重新修改老程序时出现了上面的错误,排查过后最终找到问题所在:root帐户默认不开放远程访问权限,所以需要修改一下相关权限. 打开MySQL目录下的my.ini文件(win10默认安装在C:\Pro ...

  7. centos下MySQL Workbench连接时崩溃的解决方法

    在centos6.5中使用MySQL Workbench 6.3.8链接数据库崩溃,如果是在终端使用命令“mysql-workbench”打开的话会有如下错误提示: /usr/libexec/mysq ...

  8. MySQL 线程池&连接池&长连接&短连接

    线程池 简介 1.mysql每连接每线程,mysql都分配一个单独的线程,该线程处理客户端发来的所有命令 2.每个线程会占用一定的系统资源,线程数越多消耗的系统资源也越多 3.线程的创建和销毁有一定的 ...

  9. Mysql:mysql5.7长时间不连接失效问题

    问题 mysql5数据库连接超时问题:待机一晚上后,第二天早上第一次登录总是失败. 查看日志发现如下错误: "com.mysql.jdbc.exceptions.jdbc4.Communic ...

随机推荐

  1. NETGEAR路由器登录不上 重新获取ip

    当NETGEAR路由器更改了"局域网IP配置",或者重启之后,会出现登录不上的情况 释放IP地址 # ipconfig /release 重新获取 # ipconfig /rene ...

  2. SAS.EnhancedEditor.dll 已加载,但找不到入口点DLLRegisterServer

    SAS.EnhancedEditor.dll 已加载,但找不到入口点DLLRegisterServer 重新安装EnhancedEditor 安装Microsoft.NET Framework 3.5 ...

  3. 【Struts2】Ognl与ValueStack

    一.OGNL 1.1 概述 1.2 OGNL 五大类功能 1.3 演示 二.ValueStack 2.1 概述 2.2 ValueStack结构 2.3 结论 2.3 一些问题 三.OGNL表达式常见 ...

  4. 【异常】ssh无法登录验证,非root用户ssh本机无法成功

    1 自己搭建的是伪分布式环境,需要以非root用户启动Hadoop集群,之前root已经配置了ssh免密登录,但是自己切换到hdfs用户重新生成了一套ssh key, 但是切换到hdfs始终无法成功登 ...

  5. LintCode上的一道算法面试题: 数字的统计

    说到数字的统计,小时候的数学课大家都应该有学过,但数字太多太复杂的,手动肯定耗时间不说还很容易出错.所以今天分享一下如何用程序来完成. Have you met this question in a ...

  6. 03_Redis_String命令

    一:Redis命令---String命令:Redis 字符串数据类型的相关命令用于管理 redis 字符串值 字符串类型是Redis中最为基础.常用的数据存储类型,字符串在Redis中是二进制安全的, ...

  7. ao的mobile解决方案

    http://aicdg.com/ue4-msaa-depth/ http://aicdg.com/vulkan-mass-shader-resolve/ ao两篇paper 分bake和realti ...

  8. Wind Simulation in 'God of War'(GDC2019 战神4风力场模拟)

    Wind Simulation in 'God of War'(GDC2019) 战神4中的风力场模拟 这次带来的分享的主题是,圣莫妮卡工作室他们在战神4中关于GPU模拟风力场. 演讲者Rupert ...

  9. [2019牛客多校第二场][G. Polygons]

    题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...

  10. Android控件_RecycleView+CarView+Palette联合应用

    最终效果 表格布局 垂直布局 横向布局 添加引用 build.gradle implementation 'com.android.support:recyclerview-v7:28.0.0' im ...