行锁的三种算法

一、Record Lock:单个记录上的锁

   Record Lock总是会锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。

、Gap Lock:间隙锁

   设计目的:是为了解决Phantom Problem(幻象/幻读),利用这种锁技术,锁定的不是单个值,而是一个范围。

三、Next-Key Lock:Gap Lock+Record Lock

   Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在此种算法下,InnoDB对于行的查询都是采用这种锁定算法。

  例如:

    有10、11、13、20这四个值,那么索引可能被Next-Key Locking的区间为:

    1、(-∞,10]

    2、(10,11]

    3、(11,13]

    4、(13,20]

    5、(20,+∞)

  除了Next-Key Locking,还有Previous-Key Locking,如上面的例子,可锁定的区间为:

    1、(-∞,10)

    2、  [10,11)

    3、  [11,13)

    4、  [13,20)

    5、  [20,+∞)

  然而,当查询的索引含有唯一属性时,InnoDB存储引擎对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。如表中有1,2,5的id数据:

  

  会话A首先对a=5进行X锁。而由于a是主键且唯一,因此锁定的仅是5这个值,而不是(2,5)的范围,这样在B中插入值4不会阻塞,可以立即插入并返回。即锁定由Next-Key Lock算法降级为Record Lock,从而提高了并发性。

   Next-Key Lock降级为Record Lock仅在查询的列唯一索引的情况下。

  若是辅助索引,则情况会完全不同如:

  CREATE TABLE z(a INT,b INT,PRIMARY KEY(a),KEY(b))

  INSERT INTO z SELECT 1,1;

  INSERT INTO z SELECT 3,1;

  INSERT INTO z SELECT 5,3;

  INSERT INTO z SELECT 7,6;

  INSERT INTO z SELECT 10,8;

  表z的b列是辅助索引,若在会话A中执行下面的SQL:

  SELECT * FROM z WHERE b=3 FOR UPDATE;

  这是Sql语句通过索引列b进行查询,因此其使用传统的Next-Key Locking加锁,并且由于两个索引,其需要分别进行锁定。对于聚集索引,其仅对a等于5的索引加上record Lock对于辅助索引,其加上的是Next-Key Lock,锁定的范围是(1,3),需要注意的是,InnoDB存储引擎还会对辅助索引下一个键值加上gap lock,即还有一个辅助索引的范围为(1,6)的锁,因此,在B会话中运行下面的Sql语句,都会被阻塞:

  SELECT * FORM z WHERE a=5 LOCK IN SHARE MODE;

  INSERT INTO z SELECT 4,2;

  INSERT INTO z SELECT 6,5;

  而执行下面的语句,不会阻塞:

  INSERT INTO z SELECT 8,6;

  INSERT INTO z SELECT 2,0;

  INSERT INTO z SELECT 6,7;

 

  在默认的事务隔离级别下,即REPEATABLE READ下,InnoDB存储引擎采用Next-Key Locking机制来避免Phantom Problem(幻象问题)

 

posted @ 2019-07-04 16:14  hyunbar  阅读(1361)  评论(1编辑  收藏  举报