innodb next-key lock引发的死锁现象解析
发布时间:2022-04-12 18:49:21 所属栏目:MySql教程 来源:互联网
导读:这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。 数据库的事务隔离级别是RR。 建测试表: CREATE TABLE `LockTest` ( `order_id` varchar(20) NOT NULL, `id` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `idx_order
这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。 数据库的事务隔离级别是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 测试结果: 事务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,上述事务会各自成功运行,不会互相影响。 ![]() (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |