目的

为了理解MySQL在执行大SQL时,对执行CTRL+C产生的疑惑,本文通过实验测试和源码分析两个方面,对MySQL处理CTRL+C的详细过程进行分析和讲解,从而解除DBA及开发人员对CTRL+C的误解。

测试

首先,基于线上数据库版本,分别使用MySQL客户端版本5.5.20和5.0.77进行实验测试,一方面排除不同数据库客户端版本造成的差异,另一方面,深入了解不同版本执行CTRL+C产生的差异。

MySQL客户端5.5.20

使用MySQL客户端5.5.20在Session1中执行select sleep(100)语句,在Session2中执行show processlist语句;然后在Session1中执行CTRL+C,在Session中执行show processlist语句,查看当前连接的线程。执行的图如下所示:

Session1

mysql> select sleep(100);

Ctrl-C -- sending "KILL QUERY 153779" to server ...

Ctrl-C -- query aborted.

ERROR 2013 (HY000): Lost connection to MySQL server during query

Session2:

mysql> show processlist;
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+-------------------+-----------+---------------+-----------+
| Id     | User        | Host            | db   | Command     | Time    | State                                                                       | Info              | Rows_sent | Rows_examined | Rows_read |
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+-------------------+-----------+---------------+-----------+
| 153779 | heng.wang   | 127.0.0.1:39882 | NULL | Query       |       8 | User sleep                                                                  | select sleep(100) |         0 |             0 |         1 |
| 153780 | heng.wang   | 127.0.0.1:39883 | NULL | Query       |       0 | NULL                                                                        | show processlist  |         0 |             0 |         1 |
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+-------------------+-----------+---------------+-----------+
2 rows in set (0.00 sec)

mysql> show processlist;
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+------------------+-----------+---------------+-----------+
| Id     | User        | Host            | db   | Command     | Time    | State                                                                       | Info             | Rows_sent | Rows_examined | Rows_read |
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+------------------+-----------+---------------+-----------+
| 153780 | heng.wang   | 127.0.0.1:39883 | NULL | Query       |       0 | NULL                                                                        | show processlist |         0 |             0 |         1 |
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+------------------+-----------+---------------+-----------+
1 rows in set (0.00 sec)

从以上结果来看,Session1中执行select操作时,Session2中可以查看该连接正在执行,在Session1中执行CTRL+C时,客户端向服务器端发送KILL QUERY 命令,并且连接关闭。在Session2中可以看到执行select的连接已经关闭。

MySQL客户端5.0.77

使用客户端5.0.77执行同样的操作,执行CTRL+C后,观察执行的差异性。具体如下表中所示:

Session1

mysql> select sleep(100);

Query aborted by Ctrl+C

+------------+

| sleep(100) |

+------------+

|          1 |

+------------+

Session2

mysql> show processlist;
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+-------------------+-----------+---------------+-----------+
| Id     | User        | Host            | db   | Command     | Time    | State                                                                       | Info              | Rows_sent | Rows_examined | Rows_read |
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+-------------------+-----------+---------------+-----------+
| 153783 | heng.wang   | 127.0.0.1:45807 | NULL | Query       |       3 | User sleep                                                                  | select sleep(100) |         0 |             0 |         1 | 
| 153784 | heng.wang   | 127.0.0.1:45809 | NULL | Query       |       0 | NULL                                                                        | show processlist  |         0 |             0 |         1 | 
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+-------------------+-----------+---------------+-----------+
2 rows in set (0.00 sec)

mysql> show processlist;
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+------------------+-----------+---------------+-----------+
| Id     | User        | Host            | db   | Command     | Time    | State                                                                       | Info             | Rows_sent | Rows_examined | Rows_read |
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+------------------+-----------+---------------+-----------+
| 153783 | heng.wang   | 127.0.0.1:45807 | NULL | Sleep       |      10 |                                                                             | NULL             |         1 |             0 |         1 | 
| 153784 | heng.wang   | 127.0.0.1:45809 | NULL | Query       |       0 | NULL                                                                        | show processlist |         0 |             0 |         1 | 
+--------+-------------+-----------------+------+-------------+---------+-----------------------------------------------------------------------------+------------------+-----------+---------------+-----------+
2 rows in set (0.00 sec)

从以上结果可知,Session1上执行select时,Session2中建立查询连接;在Session1中执行CTRL+C时,显示Query被终止,并且返回执行的错误结果。在Session2中可知,连接的线程仍然存在,但是Query被终止,只是保持连接。

源码分析

为了更进一步对以上测试进行确认,查看MySQL源码进行进一步的求证,同样基于MySQL的5.5.20和5.0.77两个版本进行验证。具体如下:

MySQL 5.5.20源码

MySQL客户端主函数main中,信号函数在源码文件client/mysql.cc:1163,源码如下所示:

signal(SIGINT, handle_sigint);  // Catch SIGINT to clean up

信号处理函数handle_sigint在client/mysql.cc:1291,源码如下所示:

sig_handler handle_sigint(int sig)

{

char kill_buffer[40];

MYSQL *kill_mysql= NULL;

/* terminate if no query being executed, or we already tried interrupting */

if (!executing_query || (interrupted_query == 2))

{

tee_fprintf(stdout, "Ctrl-C -- exit!\n");

goto err;

}

kill_mysql= mysql_init(kill_mysql);

if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,

"", opt_mysql_port, opt_mysql_unix_port,0))

{

tee_fprintf(stdout, "Ctrl-C -- sorry, cannot connect to server to kill query, giving up ...\n");

goto err;

}

interrupted_query++;

/* mysqld < 5 does not understand KILL QUERY, skip to KILL CONNECTION */

if ((interrupted_query == 1) && (mysql_get_server_version(&mysql) < 50000))

interrupted_query= 2;

/* kill_buffer is always big enough because max length of %lu is 15 */

sprintf(kill_buffer, "KILL %s%lu",

(interrupted_query == 1) ? "QUERY " : "",

mysql_thread_id(&mysql));

tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n", kill_buffer);

mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer));

mysql_close(kill_mysql);

tee_fprintf(stdout, "Ctrl-C -- query aborted.\n");

return;

err:

#ifdef _WIN32

mysql_thread_end();

return;

#else

mysql_end(sig);

#endif

}

从以上源码可知,MySQL客户端在捕获信号后,将KILL QUERY 命令发送到服务器端执行,从而将Query处理KILL。

MySQL 5.0.77源码

MySQL客户端主函数main中,信号函数在源码文件client/mysql.cc:1150。源码如下所示:

signal(SIGINT, mysql_sigint);  // Catch SIGINT to clean up

信号处理函数mysql_sigint在源码文件client/mysql.cc:1214,源码如下所示:

sig_handler mysql_sigint(int sig)

{

char kill_buffer[40];

MYSQL *kill_mysql= NULL;

/* terminate if no query being executed, or we already tried interrupting */

if (!executing_query || interrupted_query++)

goto err;

kill_mysql= mysql_init(kill_mysql);

if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,

"", opt_mysql_port, opt_mysql_unix_port,0))

goto err;

/* kill_buffer is always big enough because max length of %lu is 15 */

sprintf(kill_buffer, "KILL /*!50000 QUERY */ %lu", mysql_thread_id(&mysql));

mysql_real_query(kill_mysql, kill_buffer, strlen(kill_buffer));

mysql_close(kill_mysql);

tee_fprintf(stdout, "Query aborted by Ctrl+C\n");

return;

err:

#ifdef _WIN32

mysql_thread_end();

return;

#else

mysql_end(sig);

#endif

}

通过以上源码可知,MySQL客户端捕获信号后,向服务器端发送KILL /*!50000 QUERY */ 命令并执行,从而将Query处理kill。

基于以上两个版本处理的源码可知,MySQL客户端一定会捕获CTRL+C信号,并对该信号进行处理。而对于不同版本的客户端,由于发送命令的不同,导致MySQL服务器端执行结果有所不同。

结论

通过以上测试和源码分析可知,MySQL客户端肯定会捕获CTRL+C信号,并对信号进行处理。不同的是,在MySQL 5.5.20版本的客户端中执行时,服务器端执行KILL QUERY 命令,将QUERY KILL掉,并将连接关闭。而对MySQL 5.0.77客户端中执行时,服务器端执行KILL /*!50000 QUERY */ 命令,KILL掉QUERY,但保持连接。

此外,对于update、delete数据更新操作[1],CTRL+C会将执行的操作标记为KILLED状态,然后执行回滚操作。因此,不会因为CTRL+C操作,导致数据变脏。

当mysql 遇到 ctrl+c的更多相关文章

  1. [转]Navicat for MySQL快捷键

    Navicat for MySQL快捷键 ctrl+q 打开查询窗口 ctrl+/ 注释sql语句 ctrl+shift +/ 解除注释 ctrl+r 运行查询窗口的sql语句 ctrl+shift+ ...

  2. centos 7.0 编译 安装mysql 5.6.22 过程 已完成~ 成功~ 撒花~

    mysql 下载目录/usr/local/srcmysql 解压目录 /usr/local/bin/mysql GitHub https://github.com/mysql/mysql-server ...

  3. docker上配置mysql主从复制

    1.在docker上启动2台mysql容器:(这里3306为主,3307为从) docker run -d  -e MYSQL_ROOT_PASSWORD=123456  -p 3306:3306 - ...

  4. 二进制安装mysql

    1.1 MySQL安装介绍 mysql软件下载地址信息: www.mysql.com   mirrors.sohu.com mysql软件下载完毕后,查看mysql解压后目录文件大小 1.下载解压my ...

  5. 【大数据应用技术】作业九|安装关系型数据库MySQL 安装大数据处理框架Hadoop

    本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3161 1.安装MySql 按ctrl+alt+t打开终端窗口,安 ...

  6. docker部署项目: centos+python+redis+mysql+uwsgi+nginx

    一.Centos7安装docker 1.1 环境配置 先测试是否下载了docker:查看镜像:docker images没有下载,就依次执行以下环境的安装 ①curl http://mirrors.a ...

  7. Centos5.8 安装 MySQL5.6.19

    查看已经安装的mysql: sudo yum list installed |grep mysql 删除 sudo yum remove mysql 安装 sudo rpm -ivh MySQL-se ...

  8. 原创:LNMP架构部署个人博客网站 禁止转载复制

    nginx编译安装步骤 ①. 检查软件安装的系统环境 cat /etc/redhat-release uname -r ②. 安装nginx的依赖包(pcre-devel openssl-devel) ...

  9. Docker 安装mysql8.0

    1. 下载Mysql的Docker镜像: $ docker search mysql (搜索mysql镜像) $ docker pull mysql (下载mysql镜像,默认最新版本) 2. 运行镜 ...

随机推荐

  1. Tomcat源码解析-整体流程介绍

    一.架构 下面谈谈我对Tomcat架构的理解 总体架构: 1.面向组件架构 2.基于JMX 3.事件侦听 1)面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成 ...

  2. scheme 之门

    scheme 之门 开始之前 这是一篇 Scheme 的介绍文章. Scheme 是一个 LISP 的方言, 相对于 Common LISP 或其他方言, 它更强调理论的完整和优美, 而不那么强调实用 ...

  3. 浅谈范德蒙德(Vandermonde)方阵的逆矩阵的求法以及快速傅里叶变换(FFT)中IDFT的原理

    浅谈范德蒙德(Vandermonde)方阵的逆矩阵与拉格朗日(Lagrange)插值的关系以及快速傅里叶变换(FFT)中IDFT的原理 标签: 行列式 矩阵 线性代数 FFT 拉格朗日插值 只要稍微看 ...

  4. plsql批量导入sql文件

    背景:有时候在两个数据库之间导入导出数据,不可避免的需要进行sql文件的批量导入,一个个导入效率太低,所以可以考虑批量导入的办法进行导入. 操作步骤 1.假设有三个sql脚本,分别为aa.sql,bb ...

  5. vue-cli内部webpack的打包优化

    在此之前,我们先谈谈前端项目的性能优化. 优化前端项目无非就是2方面的优化: 一.网络性能优化(重点) 减少请求数量(webpack的天职就是打包) 减少请求资源大小(压缩gzip,后端会完成) CD ...

  6. android客户端app和服务端交互token的作用

    Android客户端和服务端如何使用Token和Session niceheart关注1人评论34644人阅读2014-09-16 16:38:44   对于初学者来说,对Token和Session的 ...

  7. C语言复习---二维数组和二级指针的关系:没关系,别瞎想(重点)

    前提:一维数组和一维指针为什么可以替换使用? ] = { , , }; int *p = a; ; i < ; i++) printf("%d ", *(p + i)); 上 ...

  8. bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...

  9. lua元表详解

    元表的作用 元表是用来定义对table或userdata操作方式的表 举个例子 local t1 = {1} local t2 = {2} local t3 = t1 + t2 我们直接对两个tabl ...

  10. ActiveMQ Transport Connectors

    一,介绍 ActiveMQ的Transport Connectors 是什么? ActiveMQ是一个消息服务器.作为消息服务器,就会有生产者和消费者来使用它.生产者将消息发送给ActiveMQ,消费 ...