Mysql InnoDB行锁实现方式

 

行锁的三种算法

  • Record Lock:锁单个行记录;
  • Gap Lock:间隙锁,锁定一个范围,这个范围是(前一个值,当前值),不包含记录本身;
  • Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身,即(前一个值,当前值]。

采用Next-Key Lock的锁定技术称为Next-Key Locking。这种设计的目的是为了解决幻读(Phantom Problem)。

加锁规则:

  1. 唯一索引等值查询:
  • 当查询的记录是存在的,next-key lock 会退化成 当前记录的「记录锁」。
  • 当查询的记录是不存在的,next-key lock 会退化成 当前记录所在区间的「间隙锁」。

2. 非唯一索引等值查询:

  • 当查询的记录存在时,除了会加 next-key lock 外,还额外对下一区间加「间隙锁」,也就是会加两把锁。
  • 当查询的记录不存在时,只会加 next-key lock,然后会退化为「间隙锁」,也就是只会加一把锁。

3. 范围查询

对于给定范围中涉及到的值都加next-key lock。唯一索引在满足一些条件的时候,next-key lock 退化为间隙锁(该值不符合条件)和记录锁(只有该值符合条件);非唯一索引范围查询则不会退化。

 

如何解决幻读:

假设 表结构与数据如下

CREATE TABLE t (a INT PRIMARY KEY);
INSERT INTO t VALUES (1),(2),(5);

这时候进行一个查询

SELECT * FROM t WHERE a > 2 FOR UPDATE;

Next-Key Locking算法锁住的不是5这单个值,而是对(2, +〇〇)这个范围加了 X 锁。这样其它事务就没法在该范围内插入tuple,再次查询时不会多出额外的tuple。

在rr隔离级别下,采用Next-Key Locking;在rc隔离级别下,采用Record Lock。

行锁的实现

行锁的具体实现主体是bitmap,每条记录一个bit存储。

维护一个锁的全局hash表,key值由(space_id,page_no)计算得到,value为一个链表,存储该页锁信息。用于事务上锁时判断相应页是否存在锁冲突。

同时各个事务都会维护一个锁链表,存储该事务的锁结构。不同事务即使是对同一条记录上同样模式的锁,也需要分别创建一个锁对象。用于事务结束时释放锁。

锁重用机制:两种情况下不需要重新创建锁对象:同一个事务锁住同一个页面的记录,并且锁模式相同; 同一个事务,对于同一条记录,已有的锁强于请求的锁模式。

上行锁流程:

    1. 查找hash表,判断页面上是否有锁;
    2. 若不存在,则创建锁,将锁对象插入hash链表和相应事务的锁链表;
    3. 若存在,判断事务是否已有相同或更强的锁存在 (锁重用机制);
    4. 若上锁的记录与已有锁冲突,则创建锁,并挂起等待(全局维护一个等待对象数组);
    5. 根据页面的heap_no设置bit位,结束。
 

 

 

MySQL 是怎么加锁的? | 小林coding https://xiaolincoding.com/mysql/lock/how_to_lock.html

《MySQL技术内幕:InnoDB存储引擎》 第二版 6.4.1 行锁的3种算法

MySQL InnoDB存储引擎:行锁的3种算法

Innodb行锁源码学习(一)

 

 

 

 

 

 

posted @ 2019-03-08 23:02  papering  阅读(741)  评论(0编辑  收藏  举报