innodb next-key lock引发的死锁现象分析
发表于:2024-10-16 作者:千家信息网编辑
千家信息网最后更新 2024年10月16日,这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。数据库的事务隔离级别是RR。建测试表:CREATE TABLE `LockTest` (`order_id` varchar(20) N
千家信息网最后更新 2024年10月16日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安全错误
数据库的锁怎样保障安全
底层数据库相关的面试题
网络安全防护书籍
客户机与服务器区别
贵阳有那些软件开发公司
郑州菲特网络技术有限公司
服务器安全狗可以优化吗
异种数据库 同步算法
服务器云托管
世界和网络安全
jdbc连接数据库缺点
校园网络安全应该哪个部门负责
服务器高级安装
生动网络技术教程
网络安全方向课本
阿里云数据库怎么重置密码
amigo数据库使用教程
4g模块物联网服务器
软件公司用什么软件开发app
唐山网络技术学校
数据库超市商品管理系统代码
人民共和国网络安全法实施于
360网络安全南昌公司
服务器桥接
ntp服务器品牌
网络安全证书不受信任
河北网络安全宣传周
软件开发 mask
云怎么建立数据库
电脑进网络安全模式有什么区别
我的世界国际服务器注册