innodb next-key lock引发的死锁现象分析
发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。数据库的事务隔离级别是RR。建测试表:CREATE TABLE `LockTest` (`order_id` varchar(20) N
千家信息网最后更新 2026年11月01日innodb next-key lock引发的死锁现象分析这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。
数据库的事务隔离级别是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 执行到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,上述事务会各自成功运行,不会互相影响。
数据库的事务隔离级别是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,上述事务会各自成功运行,不会互相影响。
事务
语句
数据
数据库
级别
范围
测试
隔离
死锁
分析
成功
一行
得了
索引
阻塞
普通
也就是
也就是说
例子
原因
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
哈尔滨大商圈互联网科技有限公司
互联网的科技
科技互联网项目
互联网最新的科技有限公司
深圳互联网络科技有限公司
上海挚品互联网科技
奇酷互联网科技
以房互联网科技
鑫亿盛互联网科技
互联网前沿科技
上海亿帐通互联网科技
互联网科技公司名称
茂名市互联网科技产业园
赶超互联网科技 微信多开
互联网科技产业特征
开一家科技互联网公司需要多少钱
山东有哪些互联网科技公司
同城互联网络科技
互联网高科技绘画
互联网科技快速发展优美句子
互联网巨头反垄断金融科技
重庆威客帮互联网科技
浙江互联网科技研学营
互联网科技公司实习生
杭州壁岐互联网科技有限公司
抖集互联网科技技术咨询
互联网科技企业商标注意事项
互联网科技机房
互联网科技品牌
知域互联网科技有限公司官网