[MySQL][深入理解隔离性][下][Read View]详细讲解


1.Read View

1.是什么?

  • Read View就是事务进行 快照读 操作的时候生产的 读视图(Read View),在该事务执行快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID,这个ID是递增的,所以最新的事务,ID值越大)
  • Read View 在 MySQL 源码中,就是一个类本质是用来进行可见性判断的
    • 即:当某个事务执行快照读的时候,对该记录创建一个 Read View 读视图,把它比作条件,用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的 undo log 里面的某个版本的数据
    • 注意:Read View是事务可见性的一个类,不是事务创建出来的,就会有Read View,而是当这个事务(已经存在),首次进行快照读的时候,MYSQL形成Read View
  • 下面是 ReadView 结构,但为了减少同学们负担,我们简化一下
    class ReadView
    {
        // 省略...
    private:
        /** 高水位,大于等于这个ID的事务均不可见*/
        trx_id_t m_low_limit_id
    
        /** 低水位:小于这个ID的事务均可见 */
        trx_id_t m_up_limit_id;
    
        /** 创建该 Read View 的事务ID*/
        trx_id_t m_creator_trx_id;
    
        /** 创建视图时的活跃事务id列表*/
        ids_t m_ids;
    
        /** 配合purge,标识该视图不需要小于m_low_limit_no的UNDO LOG,
         * 如果其他视图也不需要,则可以删除小于m_low_limit_no的UNDO LOG*/
        trx_id_t m_low_limit_no;
    
        /** 标记视图是否被关闭*/
        bool m_closed;
    
        // 省略...
    };
    
    m_ids; // 一张列表,用来维护Read View生成时刻,系统正活跃的事务ID
    up_limit_id; // 记录m_ids列表中事务ID最小的ID(没有写错)
    low_limit_id; // ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1
    creator_trx_id // 创建该ReadView的事务ID
    

2.理解

  • 在实际读取数据版本链的时候,是能读取到每一个版本对应的事务ID的,即:当前记录的DB_TRX_ID

  • 那么,现在手里面有的东西就有,当前快照读的 ReadView版本链中的某一个记录的DB_TRX_ID

  • 所以现在的问题就是,当前快照读,应不应该读到当前版本记录?

    请添加图片描述

  • 对应源码策略

    • 如果查到不应该看到当前版本,接下来就是遍历下一个版本,直到符合条件,才可以看到

    • 下面的 readview 是当你进行select的时候,会自动形成

      请添加图片描述

3.整体流程

  • 假设当前有条记录:

    nameage**DB_TRX_ID(**创建该记录的事务ID)**DB_ROW_ID(**隐式主键)**DB_ROLL_PTR(**回滚指针)
    张三28null1null
  • 事务操作:
    请添加图片描述

  • 事务4:修改name(张三)变成name(李四)

    • 当 事务2 对某行数据执行了快照读 ,数据库为该行数据生成一个 Read View 读视图
    // 事务2的 Read View
    m_ids; // 1,3
    up_limit_id; // 1
    low_limit_id; // 4 + 1 = 5,原因:ReadView生成时刻,系统尚未分配的下一个事务ID
    creator_trx_id // 2
    
  • 此时版本链是:
    请添加图片描述

  • 只有事务4修改过该行记录,并在事务2执行快照读前,就提交了事务
    请添加图片描述

  • 事务2在快照读该行记录的时候,就会拿该行记录的 DB_TRX_ID 去跟 up_limit_id,low_limit_id和活跃事务ID列表(trx_list)进行比较,判断当前事务2能看到该记录的版本

    // 事务2的 Read View
    m_ids;          // 1,3
    up_limit_id;    // 1
    low_limit_id;   // 4 + 1 = 5,原因:ReadView生成时刻,系统尚未分配的下一个事务ID
    creator_trx_id  // 2
    
    // 事务4提交的记录对应的事务ID
    DB_TRX_ID=4
    
    // 比较步骤
    DB_TRX_ID(4)< up_limit_id(1) ? 不小于,下一步
    DB_TRX_ID(4)>= low_limit_id(5) ? 不大于,下一步
    m_ids.contains(DB_TRX_ID) ? 不包含,说明,事务4不在当前的活跃事务中
    
    // 结论
    故,事务4的更改,应该看到
    所以事务2能读到的最新数据记录是事务4所提交的版本,而事务4提交的版本也是全局角度上最新的版本
    

2.RR与RC的本质区别

1.当前读和快照读在RR级别下的区别

  • select * from user lock in share mode;以加共享锁方式进行读取,对应的就是当前读

  • 测试表

    --设置RR模式下测试
    mysql> set global transaction isolation level REPEATABLE READ;
    
    --重启终端
    mysql> select @@tx_isolation;
    +-----------------+
    | @@tx_isolation  |
    +-----------------+
    | REPEATABLE-READ |
    +-----------------+
    
    --依旧用之前的表
    create table if not exists account(
        id int primary key,
        name varchar(50) not null default '',
        blance decimal(10,2) not null default 0.0
    )ENGINE=InnoDB DEFAULT CHARSET=UTF8;
    
    --插入一条记录,用来测试
    mysql> insert into user (id, age, name) values (1, 15,'黄蓉');
    
  • 测试用例1-表1:
    请添加图片描述

  • 测试用例2-表2:
    请添加图片描述

  • 用例1与用例2:唯一区别仅仅是 表1 的事务B在事务A修改age前快照读过一次age数据,而 表2 的事务B在事务A修改age前没有进行过快照读

  • 结论:

    • 事务中快照读的结果是非常依赖该事务首次出现快照读的地方
      • 即某个事务中首次出现快照读,决定该事务后续快照读结果的能力
    • delete同样如此

2.RR与RC的本质区别

  • 正是Read View生成时机的不同,从而造成RC,RR级别下快照读的结果的不同
  • 在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View,将当前系统活跃的其他事务记录起来
    • 此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见
    • 即:RR级别下,快照读生成Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
  • 在RC级别下的事务中,每次快照读都会新生成一个快照和Read View,这就是在RC级别下的事务中可以看到别的事务提交的更新的原因
    • 正是RC每次快照读,都会形成Read View,所以,RC才会有不可重复读问题
  • 总结:
    • 在RC隔离级别下,是每个快照读都会生成并获取最新的Read View
    • 而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View
  • 37
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
### 回答1: MySQLRead view是InnoDB存储引擎实现MVCC(多版本并发控制)的一部分。它主要用于支持在并发读取事务数据时保证数据的一致。在MVCC中,每个事务都可以看到数据库中的一个快照版本。在并发读取时,Read view可以确保每个事务看到的数据版本是相同的,从而确保数据的一致Read view是一个由系统版本号和活动事务列表组成的数据结构。系统版本号表示当前数据库中的最新版本,而活动事务列表则包含正在运行的事务和已提交但尚未释放其快照版本的事务。在读取数据时,MySQL会使用当前的Read view来确定事务所能看到的数据版本,并且只返回在此版本之前提交的数据。 因此,Read viewMySQL中起着非常重要的作用,能够保证数据的一致和并发能。 ### 回答2: MySQLRead view(读视图)是一种用于查询事务中数据的逻辑快照。它的作用主要有以下几点。 首先,Read view用于解决并发事务中的读写冲突。当一个事务开始时,它会创建一个自己的Read view,该视图包含了当前事务开始时数据库中数据的一个快照。其他并发事务可以继续对数据库进行增删改操作,但读取该数据的事务只能读取到Read view中的数据。这样可以保证读取事务在并发环境下不会读到其他未提交的事务的脏数据,确保读操作的一致和准确。 其次,Read view用于实现事务的隔离级别。MySQL支持多种事务隔离级别,包括读未提交、读提交、可重复读和串行化。每种隔离级别在Read view中有不同的实现方式,从而保证不同隔离级别下的事务读取到的数据是符合要求的。 另外,Read view还可以用于MVCC(多版本并发控制)机制。MVCC在数据库中可以实现事务的并发控制,通过为每个事务分配唯一的事务标识和Read view来实现。Read view中记录了每个事务开始时数据库中数据的一个快照,可以对比该快照和数据库当前的版本,判断其他事务的读写冲突,进而进行相应的并发控制,提高数据库的并发能。 总之,MySQLRead view在并发事务中起到了保证读操作的一致隔离的作用,同时也是实现MVCC机制的重要组成部分。通过使用Read view,可以使得事务在读取数据时不会受到其他并发事务的干扰,并保持数据库的一致。 ### 回答3: MySQLRead view是指在并发读取过程中,为每个事务提供一致的读取快照。它的作用主要体现在以下几个方面: 首先,Read view可以解决读取过程中的脏读问题。当一个事务在执行过程中,其他事务可能会对相同的数据进行修改,如果没有Read view,就可能导致读取到未提交的脏数据。而通过使用Read view,每个事务都能读取到其他事务已提交的数据,避免了脏读问题的发生。 其次,Read view可以提供一致的读取视图。当一个事务开始时,Read view会记录下事务开始时数据库中所有数据的版本号。事务执行过程中,如果其他事务对数据进行了修改并提交了,那么这个事务仍然看到的是开始时的数据版本,保证了事务内部的一致。 此外,Read view还可以提高并发读取的效率。在MySQL中,Read view通过MVCC(多版本并发控制)来实现。每个事务根据开始时的版本号,只读取那些已提交版本中的数据,可以避免了锁机制的使用,从而提高了并发读取的效率。 总的来说,MySQLRead view提供了一致的读取视图,解决了并发读取过程中可能出现的脏读问题,同时还提高了并发读取的效率。它是保证数据的一致和并发的重要机制之一。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DieSnowK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值