浅谈MySQL 有哪些死锁场景
作者:萧木易 时间:2024-01-13 13:45:54
首先一起来复习一下死锁的概念:死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。
下面我们通过几个实验,来验证几种死锁场景。
1 环境准备
use martin;
drop table if exists dl;
CREATE TABLE `dl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
`c` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_c` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `dl_insert` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
`c` int(11) NOT NULL,
PRIMARY KEY (`id`),
unique key `uniq_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
insert into dl(a,b,c) values (1,1,1),(2,2,2);
drop table if exists dl_1;
create table dl_1 like dl;
insert into dl_1 select * from dl;
2 同一张表下的死锁
session1 | session2 |
begin; | begin; |
select * from dl where a=1 for update;…1 row in set (0.00 sec) | select * from dl where a=2 for update;…1 row in set (0.00 sec) |
select * from dl where a=2 for update;/* SQL1 */(等待) | |
(session2 提示死锁回滚后,SQL1 成功返回结构) | select * from dl where a=1 for update;ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
commit; | commit; |
session1 在等待 session2 释放 a=2 的行锁,而 session2 在等待 session1 释放 a=1 的行锁。两个 session 互相等待对方释放资源,就进入了死锁状态。
3 不同表下的死锁
session1 | session2 |
begin; | begin; |
select * from dl where a=1 for update; … 1 row in set (0.00 sec) | select * from dl_1 where a=1 for update; … 1 row in set (0.00 sec) |
select * from dl_1 where a=1 for update;/* SQL2 */ 等待 | |
(session2 提示死锁回滚后,SQL1 成功返回结构) | select * from dl where a=1 for update; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
commit; | commit; |
这个实验也是两个 session 互相等待对方释放资源,就进入了死锁状态。
4 间隙锁下的死锁
session1 | session2 |
set session transaction_isolation='REPEATABLE-READ'; /* 设置会话隔离级别为 RR */ | set session transaction_isolation='REPEATABLE-READ'; /* 设置会话隔离级别为 RR */ |
begin; | begin; |
select * from dl where a=1 for update; … 1 row in set (0.00 sec) | select * from dl where a=2 for update; … 1 row in set (0.00 sec) |
insert into dl(a,b,c) values (2,3,3);/* SQL1 */ 等待 | |
(session2 提示死锁回滚后,SQL1 成功返回结果) | insert into dl(a,b,c) values (1,4,4);/* SQL2 */ ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
commit; | commit; |
由于 RR 隔离级别下存在间隙锁,可以知道 SQL1 需要等待 a=2 获得的间隙锁,而 SQL2 需要等待 a=1 获得的间隙锁,两个 session 互相等待对方释放资源,就进入了死锁状态。
5 INSERT 语句的死锁
session1 | session2 | session3 |
begin; | ||
insert into dl_insert(a,b,c) value (3,3,3); | ||
insert into dl_insert(a,b,c) value (3,3,3);/* 等待 */ | insert into dl_insert(a,b,c) value (3,3,3);/* 等待 */ | |
rollback; | 执行成功 | ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
这里需要注意的是,a 字段有唯一索引。当 session1 执行完 insert 语句,会在索引 a=3 上加记录锁,当 session2 执行同样的 insert 语句时,唯一键冲突,加上读锁;同样 session3 也会加上读锁。
当 session1 回滚,session2 和 session3 都试图继续执行插入操作,都要加上写锁。此时两个 session 都要等待对方的行锁,因此出现了死锁。
一些死锁场景就介绍到这里,当然,也欢迎各位补充其他的一些死锁场景。
来源:https://blog.csdn.net/weixin_43997319/article/details/124983655
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
python 移动图片到另外一个文件夹的实例
PHPMyAdmin导入时提示文件大小超出PHP限制的解决方法
![](https://img.aspxhome.com/file/2023/1/137061_0s.png)
Django实现跨域的2种方法
关于django 数据库迁移(migrate)应该知道的一些事
python 获取网页编码方式实现代码
表单制作方式大比拼
![](https://img.aspxhome.com/file/uploadpic/20071/2007131102013522.gif)
MySQL表排序规则不同错误问题分析
SQL Server中的SELECT会阻塞SELECT吗
![](https://img.aspxhome.com/file/2023/4/86894_0s.png)
为网站代码块pre标签增加一个复制代码按钮代码
![](https://img.aspxhome.com/file/2023/4/136924_0s.png)
python urllib urlopen()对象方法/代理的补充说明
成功实现ajax,xmlhttp跨域访问(php,asp,jsp)
什么是XSL?
Python实现约瑟夫环问题的方法
js replace()去除代码中空格的实例
sql 自定义百分比转换小数函数代码
mysql数据库修改数据表引擎的方法
js 可选链操作符的使用
![](https://img.aspxhome.com/file/2023/2/56002_0s.jpg)