两万字详解InnoDB的锁( 七 )

  • 根据加锁原则 2 :只有访问到的对象才会加锁,事务A的这个查询使用了覆盖索引,没有回表,并不需要访问主键索引,因此主键索引上没有加任何锁,事务会话B是对主键id的更新,因此事务会话B的update不会阻塞 。
  • 但是事务会话C,要插入一个(6,6,6) 的记录时,会被事务会话A的间隙锁(5,10)锁住,因此事务会话C阻塞了 。
  • 4.3 案例三:主键索引范围锁主键范围查询又是怎么加锁的呢?比如给定SQL:
    select * from t5 where id>=10 and id<11 for update;按顺序执行事务会话A、B、C,如下:
    两万字详解InnoDB的锁

    文章插图
     
    执行结果如下:
    两万字详解InnoDB的锁

    文章插图
     
    发现事务会话B中,插入12,即insert into t5 values(12,12,12);时,阻塞了,而插入6,insert into t5 values(6,6,6);却可以顺利执行 。同时事务C中,Update t5 set d=d+1 where id =15;也会阻塞,为什么呢?
    事务会话A执行时,要找到第一个id=10的行:
    • 根据加锁原则1:加锁单位是next-key lock,因此会加上next-key lock(5,10] 。
    • 又因为id是主键,也就是唯一值,因此根据优化1:索引上的等值查询,给唯一索引加锁时,next-key lock退化为行锁(Record lock) 。所以只加了id=10这个行锁 。
    • 范围查找就往后继续找,找到id=15这一行停下来,因此还需要加next-key lock(10,15] 。
    事务会话A执行完后,加的锁是id=10这个行锁,以及临键锁next-key lock(10,15] 。这就是为什么事务B插入6那个记录可以顺利执行,插入12就不行啦 。同理,事务C那个更新id=15的记录,也是会被阻塞的 。
    4.4 案例四:非唯一索引范围锁如果是普通索引,范围查询又加什么锁呢?按顺序执行事务会话A、B、C,如下:
    两万字详解InnoDB的锁

    文章插图
     
    执行结果如下:
    两万字详解InnoDB的锁

    文章插图
     
    发现事务会话B和事务会话C的执行SQL都被阻塞了 。
    这是因为,事务会话A执行时,要找到第一个c=10的行:
    1. 根据加锁原则1:加锁单位是next-key lock,因此会加上next-key lock(5,10] 。
    又因为c不是唯一索引,所以它不会退化为行锁 。因此加的锁还是next-key lock(5,10] 。2. 范围查找就往后继续找,找到id=15这一行停下来,因此还需要加next-key lock(10,15] 。
    因此事务B和事务C插入的insert into t5 values(6,6,6);和Update t5 set d=d+1 where c =15; 都会阻塞 。
    4.5 案例五:唯一索引范围锁 bug前面四种方案中,加锁的两个原则和两个优化都已经用上啦,那个唯一索引范围bug是如何触发的呢?
    按顺序执行事务会话A、B、C,如下:
    两万字详解InnoDB的锁

    文章插图
     
    执行结果如下:
    两万字详解InnoDB的锁

    文章插图
     
    发现事务B的更新语句Update t5 set d=d+1 where id =20; 和事务Cinsert into t5 values(18,18,18);的插入语句均已阻塞了 。
    这是因为,事务会话A执行时,要找到第一个id=15的行,根据加锁原则1:加锁单位是next-key lock,因此会加上next-key lock(10,15] 。因为id是主键,即唯一的,因此循环判断到 id=15 这一行就应该停止了 。但是实现上,InnoDB 会往前扫描到第一个不满足条件的行为止,直到扫描到id=20 。而且由于这是个范围扫描,因此索引id上的(15,20]这个 next-key lock 也会被锁上 。
    所以,事务B要更新 id=20 这一行时,会阻塞锁住 。同样地事务会话C要插入id=16的一行,也会被锁住 。
    4.6 案例六:普通索引上存在"等值"的例子如果查询条件列是普通索引,且存在相等的值,加锁又是怎样的呢?
    在原来t5表的数据基础上,插入:
    insert into t5 values(28,10,66);则c索引树如下:
    两万字详解InnoDB的锁

    文章插图
     
    c索引值有相等的,但是它们对应的主键是有间隙的 。比如(c=10,id=10)和(c=10,id=28)之间 。
    我们来看个例子,按顺序执行事务会话A、B、C,如下:
    两万字详解InnoDB的锁

    文章插图
     
    执行结果如下:
    两万字详解InnoDB的锁


    推荐阅读