温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

innodb next-key lock引发的死锁现象分析

发布时间:2020-08-08 15:06:09 来源:ITPUB博客 阅读:365 作者:花花蘑菇 栏目:MySQL数据库
这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。

数据库的事务隔离级别是RR。

建测试表:
CREATE TABLE `LockTest` (
   `order_id` varchar(20) NOT NULL,
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
   PRIMARY KEY (`id`),
   KEY `idx_order_id` (`order_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

测试步骤:
事务1 事务2

begin

delete from LockTest where order_id =  'D20'

 
 

 

begin

delete from LockTest where order_id =  'D19'

insert into LockTest (order_id) values ('D20')

 
 

insert into LockTest (order_id) values ('D19')

commit

commit


测试结果:
事务1 执行到insert语句会block住,事务2执行insert语句会提示死锁错误。

原因分析:
1、首先看测试表的建表语句,id是主键索引,同时该主键是自增主键。order_id是普通索引。
2、事务1执行delete from LockTest where order_id =  'D20';语句时,由于数据库的隔离级别是RR,因此此时事务1在主键id上获得了一个next-key lock,这个锁的范围是[16, +∞)。
   这个16就来自于AUTO_INCREMENT=16,因为LockTest目前是张空表。
3、同理,事务2执行delete from LockTest where order_id =  'D19';语句时,由于数据库的隔离级别是RR,事务2在主键id上也获得了一个next-key lock,这个锁的范围是[16, +∞)。
   也就是说此时,事务1和事务2获得的锁是一样的。
4、事务1继续执行insert into LockTest (order_id) values ('D20');语句,这个时候由于该语句企图往LockTest表insert一行id=16,order_id=D20的数据,
   但是由于在事务2的delete语句中,主键id上已经有了一个范围为[16, +∞)的锁,导致事务1此时想插入数据插不进去,被阻塞了。

5、继续事务2的插入语句insert into LockTest (order_id) values ('D19'); 该插入语句同样也想LockTest表insert一行id=16,order_id=D19的数据,
   
但是由于由于在事务1的delete语句中,主键id上已经有了一个范围为[16, +∞)的锁,导致事务2此时想插入数据插不进去,被阻塞了。
   此时,可以发现,事务1和事务2的锁是互相持有,互相等待的。所以innodb判断该事务遇到了死锁,直接将事务2进行了回滚。然后回头去看事务1,
insert into LockTest (order_id) values ('D20');被成功执行。

如果你将数据库的事务隔离级别修改为RC,上述事务会各自成功运行,不会互相影响。






向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI