美文网首页面试精选
MySQL - 幻读 、间隙锁

MySQL - 幻读 、间隙锁

作者: lconcise | 来源:发表于2021-08-03 21:50 被阅读0次

    select for update 加写锁。事物提交才释放

    什么是幻读?

    产生幻读的场景:

    幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。

    幻读说明:

    1. 在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现
    2. 上面 session B 的修改结果,被 session A 之后的 select 语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”

    幻读的问题?

    1. 首先是语义上的。session A 在 T1 时刻就声明了,“我要把所有 d=5 的行锁住,不准别的事务进行读写操作”。而实际上,这个语义被破坏了。
    2. 锁的设计是为了保证数据的一致性。而这个一致性,不止是数据库内部数据状态在此刻的一致性,还包含了数据和日志在逻辑上的一致性。
      也就是说,即使把所有的记录都加上锁,还是阻止不了新插入的记录

    解决幻读

    产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)。

    间隙锁,锁的就是两个值之间的空隙

    行锁有冲突关系的是“另外一个行锁”。但是间隙锁不一样,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁之间都不存在冲突关系。

    间隙锁和行锁合称 next-key lock,每个 next-key lock 是前开后闭区间。

    间隙锁和 next-key lock 的引入,帮我们解决了幻读的问题,但同时也带来了一些“困扰”。

    间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的。

    实践

    表初始化

    CREATE TABLE z (
      id INT PRIMARY KEY AUTO_INCREMENT,
      b  INT,
      KEY b(b)
    ) ENGINE = InnoDB DEFAULT CHARSET = utf8;
    
    INSERT INTO z 
      (id, b)
    VALUES 
      (1, 2),
      (3, 4),
      (5, 6),
      (7, 8),
      (9, 10);
    
    image.png
    • session A
    BEGIN;
    SELECT * FROM z WHERE b = 6 FOR UPDATE;
    
    • session B
    INSERT INTO z VALUES (2, 4);/*success*/
    INSERT INTO z VALUES (2, 8);/*blocked*/
    INSERT INTO z VALUES (4, 4);/*blocked*/
    INSERT INTO z VALUES (4, 8);/*blocked*/
    INSERT INTO z VALUES (8, 4);/*blocked*/
    INSERT INTO z VALUES (8, 8);/*success*/
    INSERT INTO z VALUES (0, 4);/*blocked*/
    INSERT INTO z VALUES (-1, 4);/*success*/
    

    分别执行 session B中的insert 会出现上述情况,为什么?

    加锁过程

    1. 在索引 b 上的等值查询,给索引 b 加上了 next-key lock (4, 6];索引向右遍历,且最后一个值不满足条件时退化为间隙锁;所以会再加上间隙锁 (6,8);所以索引 b 上的 next-key lock 的范围是(b=4,id=3)到(b=6,id=5)这个左开右闭区间和(b=6,id=5)到(b=8,id=7)这个开区间。(读起来有点绕口,看不懂的可以看下文中的图)
    2. for update 会给 b = 6 这一行加上行锁;因此 (b=6,id=5) 这一行上有行锁
    image.png

    参考博文:
    https://www.jianshu.com/p/42e60848b3a6
    https://blog.csdn.net/zcl_love_wx/article/details/82382582

    相关文章

      网友评论

        本文标题:MySQL - 幻读 、间隙锁

        本文链接:https://www.haomeiwen.com/subject/zxasvltx.html