MySQL如何加行级锁的?
10 分钟阅读
•
1217 字
+
601 词
行级锁加锁规则比较复杂,不同的场景,加锁的形式是不同的。
加锁的对象是索引,加锁的基本单位是 next-key lock
,它是由记录锁和间隙锁组合而成的,
next-keylock 是前开后闭区间
,而间隙锁是前开后开区间。
但是,
next-key lock 在一些场景下会退化成记录锁或间隙锁
。
那到底是什么场景呢?总结一句在
能使用记录锁或者间隙锁就能避免幻读现象
的场景下,next-keylock 就会退化成记录锁或间隙锁。
当我们用唯一索引进行等值查询的时候,查询的记录存不存在,加锁的规则也会不同:
当
查询的记录
是**「存在」
的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock
会退化成「记录锁」。
当
查询的记录
是
「不存在」**的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的next-key lock
会退化成「间隙锁」
范围查询和等值查询的加锁规则是不同的。
当唯一索引进行范围查找时,
会对每一个扫描到的索引加 next-key 锁
,然后如果遇到下面这些情况,当唯一索引进行范围查询时,退化成记录锁或者间隙锁:
当我们用非唯一索引进行等值查询的时候,
因为存在两个索引,一个是主键索引,一个是非唯一索引(辅助索引)
,所以在加锁时,
同时会对这两个索引都加锁
,但是
对主键索引加锁的时候,只有满足查询条件的记录才会对它们的主键索引加锁。
针对非唯一索引等值查询时,查询的记录存不存在,加锁的规则也会不同:
非唯一索引范围查询,索引的next-key lock不会有退化为间隙锁和记录锁的情况。
如果锁定读查询语句,没有使用索引列作为查询条件,或者查询语句没有走索引查询,导致扫描是全表扫描。那么,每一条记录的索引上都会加next-key锁,这样就相当于锁住的全表,这时如果其他事务对表进行增删改操作,都会被阻塞。
重点在于 执行update,delete,select for update等具有加锁性质的语句,一定要检查语句是否走了索引,如果是全表扫描的话,会对每一个索引加next-key锁,相当于把整个表锁住。
唯一索引等值查询
唯一索引范围查询
- 情况一:针对「大于等于」的范围查询,因为 存在等值査询的条件 ,那么 如果等值查询的记录是存在于表 中,那么该记录的索引中的 next-key 锁会 退化成记录锁 。
-
情况二:针对「小于或者小于等于」的范围查询,要看条件值的记录是否存在于表中:
- 当 条件值的记录不在表 中,那么不管是「小于」还是「小于等于」条件的范围查询, 扫描到终止范围查询的记录时,该记录的索引的 next-key 锁会退化成间隙锁 ,其他扫描到的记录,都是在这些记录的索引上加 next-key 锁。
-
当
条件值的记录在表
中,
- 如果是「小于」条件的范围查询,扫描到终止范围查询的记录时, 该记录的索引的 next-key 锁会退化成间隙锁 ,其他扫描到的记录,都是在这些记录的索引上加 next-key锁:
- 如果「小于等于」条件的范围查询,扫描到终止范围查询的记录时, 该记录的索引 next-key 锁不会退化成间隙锁 。其他扫描到的记录,都是在这些记录的索引上加 next-key 锁。
非唯一索引等值查询
- 当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是 非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描 ,然后在扫描的过程中, 对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录该二级索引的 next-key 锁会退化成间隙锁 。同时,在 符合查询条件的记录的主键索引上加记录锁。
- 当查询的记录「不存在」时,**扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。**因为不存在满足查询条件的记录, 所以不会对主键索引加锁。
非唯一索引范围查询
没有加索引的查询