innodb next-key lock引发的死锁现象分析
发表于:2025-11-12 作者:千家信息网编辑
千家信息网最后更新 2025年11月12日,这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。数据库的事务隔离级别是RR。建测试表:CREATE TABLE `LockTest` (`order_id` varchar(20) N
千家信息网最后更新 2025年11月12日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安全错误
数据库的锁怎样保障安全
软件开发都需要什么软件
java怎么搞网络安全
广州聚焦网络技术骗局
服装数据库数据字典
北京淘聘网络技术有限公司
网络安全主题综合实践活动
厦门银行软件开发岗
滨海新区项目网络技术售后保障
各个专业的数据库
最新数据库
一个软件开发资料
打开服务器管理器在哪里找
长理网络安全知识竞赛答案
山东网络技术学院官网
数据库实体模型是什么
研究性课题网络安全宣传活动
国家实施网络安全分级制度
网络安全好学嘛
烟囱式软件开发到平台式
网络安全产品发展趋势论文
安徽互联网软件开发靠谱吗
女性软件开发后想转行做什么
hp服务器com1
医院网络安全管理员需要的技能
计算机网络技术和算法
腾讯云服务器系统官方网站下载
与软件开发相当的文科专业
今年是第几个首都网络安全日
本地服务器硬件部署方案
17173魔兽数据库