一、前言
在我们运维MySQL的时候,总会遇到各种情况导致程序和MySQL之间的会话异常中断,比如
假如强制关闭应用
假如client机器突然崩溃宕机/断电
假如网络发生抖动/网卡发生故障
机房级别断网
那么此时正在MySQL中执行的事务会何表现?
二、实践
设计一个案例模拟client 在MySQL中执行事务,但是client机器突然down机,导致会话异常中断。
client 192.168.56.102
MySQL 192.168.56.101
client 连接db 执行 select for update 动作给记录加上锁,当然实际上 也可以是update,delete 这样的动作给记录加上锁。
然后关闭client机器模拟断电,断网。
此时server端 网络层的连接状态依然是 ESTABLISH 数据库中的事务处于running状态。
再开启另外一个会话,对t1表进行加锁需要等待,说明断网之后的事务依然处于活跃状态。
ok 表演结束 ,我们接下来继续分析网络断开,事务为啥没有退出?
三、分析
3.1 服务端为什么没有退出这个事务呢?
MySQL普通的会话连接没有保活机制,即没有设置socket属性,也没有设置心跳机制。如果网络连接异常断开服务端不能及时探测到该异常。更进一步,我们通过 TCP 关闭的四次握手来看
网络异常的时候,TCP连接的状态还是ESTABLISHED,说明 server 和 client 任何一方都没有主动发送FIN包,服务端还在等待 client端 发送数据,此时的 MySQL 事务无法直接退出。
3.2 事务在网络断开后如何处理
事务正在执行
一个连接进行事务后,如果事务语句正在执行,那么网络断开后会在语句执行完成后回滚掉。因为执行状态包不能送达客户端,因此会感知到这种网络断开的错误。调试堆栈信息参考 堆栈1。
if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))