一次诡异的数据库“死锁”,问题究竟在哪里?

程序死锁的问题,很难调试,看进程堆栈,看各个线程与锁的状况,对照代码进行排查。shell

数据库死锁的问题,更难,看不了数据库堆栈,也看不了数据库线程与锁,更难以对照代码排查。数据库

前段时间,和一个朋友讨论了一个“疑似”数据库死锁的问题,最后进行试验与排查,找到了问题所在。session

场景以下:

一次诡异的数据库“死锁”,问题究竟在哪里?
同一个表,高并发事务,事务内先插入一条记录,再更新这条记录:
(1)若是更新的是惟一索引,有异常;
(2)若是更新的是自增主键,就没有异常;
画外音:先不要被“dead lock”描述所迷惑,是死锁问题,阻塞问题,仍是其余异常,还另说。架构

一次诡异的数据库“死锁”,问题究竟在哪里?
并且,据朋友所述,还可以复现:
(1)开启事务;
(2)插入记录;
(3)sleep 5秒;
(4)修改被插入的记录;
在并发时稳定复现。并发

根据朋友的描述,在线下开了多个MySQL客户端进行了并发模式测试,结果还挺出乎意料的。ide

第一步:数据准备

create table t (
id int(20) primary key AUTO_INCREMENT,
cell varchar(20) unique
)engine=innodb;

新建表:
(1)存储引擎是innodb,MySQL版本是5.6;
(2)id字段,自增主键;
(3)cell字段,惟一索引;高并发

start transaction;
insert into t(cell) values(11111111111);
insert into t(cell) values(22222222222);
insert into t(cell) values(33333333333);
commit;

插入一些测试数据。

第二步:session参数设置
事务的隔离级别,事务的自动提交等参数设置不当,都会对实验的结果产生影响,询问了朋友,事务的隔离级别是RR(repeatable read)。测试

set session autocommit=0;
set session transaction isolation level repeatable read;

每个session启动后:
(1)关闭自动提交;
(2)把事务隔离级别设为RR;
一次诡异的数据库“死锁”,问题究竟在哪里?线程

show session variables like "autocommit";
show session variables like "tx_isolation";

不放心的话,能够用上面两个语句查询确认。调试

第三步:多个终端session模拟并发事务

一次诡异的数据库“死锁”,问题究竟在哪里?
如上图,用SecureCRT开启两个窗口:
(1)窗口A,先启动事务,并插入记录;
(2)窗口B,再启动事务,也插入记录;
(3)窗口A,修改插入的记录;
(4)窗口B,也修改插入的记录;

奇怪的现象发生了,若是并发事务的update语句:
(1)更新条件是cell,就会发生异常;
(2)更新条件是id,就一切正常;

按道理,插入不冲突的记录,而后修改这条记录,行锁不该该冲突呀?惟一索引,主键索引怎么会有差别呢?是否有关?是死锁,仍是其余缘由?

你们帮忙分析分析,到底问题在哪里呢?

有可能,要用到这里的知识:
《MySQL并发控制与锁+调试MySQL死锁d方法》
一次诡异的数据库“死锁”,问题究竟在哪里?
架构师之路-分享技术思路
相关推荐:
《写一个cache,要掌握哪些技术点》
《6条shell小技巧 | 1分钟系列》

欢迎讨论,下一篇,和你们同步结果。画外音:思考以后,印象更加深入。

相关文章
相关标签/搜索