加锁顺序
普通select查询
- 获取表级锁: MDL读锁
- 不需要其他锁: 因为使用的是MVCC,所以不需要行锁 ps: 很多地方都说使用了MVCC就不需要加锁,实际上是不需要行锁,MDL读锁还是需要的
共享读select in share mode
- 首先获取表级锁: MDL写锁
- 再获取表级锁: 意向共享锁
- 再获取行级锁: 根据不同语句获取对应的行锁和间隙锁
insert插入
- 首先获取表级锁: MDL写锁
- 再获取表级锁: 意向排它锁
- 再获取行级锁: 插入意向锁
update/delete
- 首先获取表级锁: MDL写锁
- 再获取表级锁: 意向排它锁
- 再获取行级锁: 根据不同语句获取对应的行锁和间隙锁
行锁加锁规则
两个“原则”、两个“优化”和一个“bug”
- 原则 1:加锁的基本单位是 next-key lock。希望你还记得,next-key lock 是前开后闭区间。
- 原则 2:查找过程中访问到的对象才会加锁。
- 优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。
- 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。
- 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。
锁冲突和兼容规则
- MDL: MDL只与MDL存在冲突,读锁兼容读锁,写锁与读锁或写锁都不兼容
- 意向锁规则: (IS 意向共享锁, IX意向排它锁, S共享锁, X排它锁)
IS | IX | S | X | |
---|---|---|---|---|
IS |
|
|
| – |
IX |
|
| – | – |
S |
| – |
| – |
X | – | – | – | – |
- 行锁规则: record lock行锁,gap lock间隙锁, insert intension lock间隙锁, next key lock(行锁 间隙锁)
加的锁 已存在的锁 | record lock | gap lock | insert intention lock | next key lock |
---|---|---|---|---|
record lock | – |
|
| – |
gap lock |
|
|
|
|
insert intention lock |
| – |
| – |
next key lock | – |
|
| – |
参考
- MySQL实战45讲: 为什么我只改一行的语句,锁这么多?
- MySQL加锁分析