zoukankan      html  css  js  c++  java
  • 为什么说 MVCC 和 Gap Lock 解决了 MySQL 的幻读问题

    周一的时候被问到了幻读的问题,之前都是看别人写的文章没有建套环境来实际操作一下。

    其实很多问题不仅是要看源码,还是需要动动手,光看还是会忘记。

    先说结论在忽略参数设置的情况下, MySQL 的确使用 MVCC 配合 Gap Lock 解决了 RR 隔离级别下的当前读(用 Gap Lock)和快照读(用 MVCC)的幻读问题。

    我们先来建立测试用的基础表

    CREATE TABLE `t` (
      `id` int(11) NOT NULL,
      `c` int(11) DEFAULT NULL,
      `d` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `c` (`c`)
    ) ENGINE=InnoDB;
    
    insert into t values(0,0,0),(5,5,5),
    (10,10,10),(15,15,15),(20,20,20),(25,25,25);

    MVCC 快照读解决幻读

    然后 先来看看在 RR 级别下因为 MVCC 的关系解决幻读的情况

      session1 session2 session3
    line 1

    begin;

    select * from t where d =5;

       
    line 2   update t set d = 5 where id = 0  
    line 3 select * from t where d =5;    
    line 4     insert into t value(1, 1, 5)
    line 5 select * from t where d =5;    
    line 6 commit;    

    line 1 session 1 

    mysql> begin;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from t where d = 5;
    +----+------+------+
    | id | c    | d    |
    +----+------+------+
    |  5 |    5 |    5 |
    +----+------+------+
    1 row in set (0.00 sec)

    line 2 session 2 执行后 line 3 session 1

    mysql> update t set d = 5 where id = 0;
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> select * from t where d = 5;
    +----+------+------+
    | id | c    | d    |
    +----+------+------+
    |  5 |    5 |    5 |
    +----+------+------+
    1 row in set (0.00 sec)

    line 4 session3 执行后的 line 5 session 1

    mysql> insert into t value (1, 1, 5);
    Query OK, 1 row affected (0.01 sec)
    
    mysql> select * from t where d = 5;
    +----+------+------+
    | id | c    | d    |
    +----+------+------+
    |  5 |    5 |    5 |
    +----+------+------+
    1 row in set (0.00 sec)

    可以看到在快照读的情况下, RR 隔离级别可以通过 MVCC 保护自己事务内的数据,无论外面如何修改。

    Gap Lock 解决当前读下的幻读

    当前读的情况下我们就无法达到刚才的效果了,还是刚才那个流程

      session1 session2 session3
    line 1

    begin;

    select * from t where d =5 for update;

       
    line 2   update t set d = 5 where id = 0  
    line 3 select * from t where d =5 for update;    
    line 4     insert into t value(1, 1, 5)
    line 5 select * from t where d =5 for update;    
    line 6 commit;    

    我为 session 1里的所有查询都加上当前读的 for update 。会发现从 session2 开始就被阻塞了。

    这里就是在执行 select * from t where d = 5 for update 的时候因为 d 上没有索引的关系,MySQL 直接将该字段的全部范围都打上了 Gap Lock,所以无法执行插入更新操作,就阻塞住了。

    可以看到通过 Gap Lock 我们即使在当前读也被阻止了幻读,因为 Gap Lock 的关系 session c 尝试往里插入新数据也同样被阻塞从而保证了数据的一致性。

    所以回到文中开始的那个问题,MySQL 在 RR 事务隔离级别下,的确通过 MVCC 以及 Gap Lock 解决了幻读问题,是我答错了。

  • 相关阅读:
    延时调用的php代码
    mysql 官网下载太慢了,来这里!!!
    解决react-native 运行报错:Entry, ":CFBundleIdentifier", Does Not Exist
    mongodb增删改查常用命令总结
    Linux 查看文件内容(8)
    Linux mv命令(7)
    Linux文件拷贝(6)
    Linux 创建与删除(5)
    Linux cd命令(4)
    ls 命令通配符(3)
  • 原文地址:https://www.cnblogs.com/piperck/p/13042303.html
Copyright © 2011-2022 走看看