字节面试题
在可重复隔离级别下,这种情况会发生什么?
答案:死锁
下面我们用一个具体的例子来展示:
首先我们有一张这样的表
下面我们来执行一些语句,
可以看到结果输出了,检测到发生了死锁
Deadlock found when trying to get lock; try restarting transaction
下面具体分析,首先给出执行流程
事务A | 事务B | |||
---|---|---|---|---|
1 | begin; | begin; | ||
2 | update user set age = 30 where id = 25; | |||
3 | update user set age = 30 where id = 26; | |||
4 | insert into user(id,name,age,email) values(25,"dcf",30,"123@qq.com"); | |||
5 | insert into user(id,name,age,email) values(26,"dcf",30,"123@qq.com"); | |||
下面分析每个阶段的加锁情况
- 阶段2 update user set age = 30 where id = 25;
通过select * from performance_schema.data_locks\G;
来查看加锁的情况:
可以看到加了两种锁,一种是表锁,意向排他锁,可以看到成功获取了这把锁,
LOCK_TYPE: TABLE
LOCK_MODE: IX
LOCK_STATUS: GRANTED
LOCK_DATA: NULL
另一种是记录锁,排他锁,间隙锁,锁住的范围是(20,30),可以看到成功获取到了这把锁,
LOCK_TYPE: RECORD
LOCK_MODE: X,GAP
LOCK_STATUS: GRANTED
LOCK_DATA: 30
- 阶段3 update user set age = 30 where id = 26;
通过select * from performance_schema.data_locks\G;
来查看加锁的情况:
可以看到加了两种锁,一种是表锁,意向排他锁,可以看到成功获取了这把锁,
LOCK_TYPE: TABLE
LOCK_MODE: IX
LOCK_STATUS: GRANTED
LOCK_DATA: NULL
另一种是记录锁,排他锁,间隙锁,锁住的范围是(20,30),可以看到成功获取到了这把锁,
LOCK_TYPE: RECORD
LOCK_MODE: X,GAP
LOCK_STATUS: GRANTED
LOCK_DATA: 30
- 阶段4 insert into user(id,name,age,email) values(25,"dcf",30,"123@qq.com");
- 阶段5 insert into user(id,name,age,email) values(26,"dcf",30,"123@qq.com");
可以看到第3,4阶段双方都在等待锁,产生了死锁现象,
这个死锁的产生是由于,在阶段1,2双方持有了(20,30)区间的间隙锁,阶段3,4的插入操作会产生插入意向锁,这两个插入意向锁都被对方的间隙锁所阻塞,从而产生了死锁。
插入意向锁介绍
本文使用了间隙锁会阻塞插入意向锁这个特点