innodb next-key lock引发的死锁现象分析
发表于:2025-01-22 作者:千家信息网编辑
千家信息网最后更新 2025年01月22日,这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。数据库的事务隔离级别是RR。建测试表:CREATE TABLE `LockTest` (`order_id` varchar(20) N
千家信息网最后更新 2025年01月22日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安全错误
数据库的锁怎样保障安全
个人电脑 网站服务器
荣耀7x连接不到服务器
服务器如何启动
洛阳软件开发最新招聘
战神引擎芒果数据库教程
dbs数据库系统是采用了
软件开发行业的看法
我的世界梦世界服务器大全手机版
广州紫网网络技术有限公司
服务器能耗计算
.db 数据库
大学生网络安全手抄报模板
崇州网络安全教育
武装突袭3服务器
有关网络安全的倡议书100
数据库er图在线创建
通过下拉表格筛选相应数据库
网络安全月度例会纪要
网络安全project
二道区通用网络技术品质保障
中美网络安全基础
大话西游手游吉祥如意服务器
用服务器做平面设计
数据库备份服务器搭建
oracle更新数据库时间
数据库及其建立过程试讲视频
中山单片机测试软件开发
数据库对java
nx 数据库中不存在首选项
sqlite导出数据库