乐趣区

关于mysql:MySQLMVCC全网最详细解读

什么是 MVCC

在学习 MVCC 前,先理解一下以后读和快照读

  • 以后读

    比方 lock in share mode(共享锁),for update,update,delete,insert(排它锁)这些操作都是一些以后读,以后读的定义就是读取以后数据的最新版本,读取时还要保障其它并发事务不能批改数据,会对读取的记录进行加锁

  • 快照读

    不加锁的 select 就是快照读,即不加锁的非阻塞读,快照读的前提是隔离级别不是串行级别,串行级别下快照读会进化为以后读。快照读的实现是基于多版本并发管制,即 MVCC。即快照读可能读取到的数据不肯定是最新版本,而有可能是之前的历史版本

MVCC 即多版本并发管制,保留无关已更改行的旧版本的信息以及反对事务性能,例如 并发和回滚,这些信息以回滚段的形式存储在 UndoLog 中。MVCC 就是为了实现读写不抵触不加锁,读也就是快照读,不是以后读

什么是 UndoLog

回滚日志(撤销日志),MVCC 的重要组成部分,单个事务对记录变更操作的记录汇合。如果另一个事务须要查看原始数据满足一致性读,则须要去 undolog 中检索,UndoLog 保留在 UndoLog Segments 中,UndoLog Segments 保留在 Rollback Segments 中,回滚段保留在 Undo 表空间和全局长期表空间中。UndoLog 个别是逻辑日志,记录数据的变更版本信息

mvcc 实现原理

基于隐式字段 +UndoLog+Read View 实现

UndoLog 中的每条记录都有暗藏字段

  • DB_TRX_ID 创立该条记录或者最初批改该条记录的事务 ID
  • DB_ROLL_PTR 回滚指针,指向以后这条记录的上一个版本
  • DB_ROW_ID 暗藏的主键

UndoLog,在 insert,update,delete 时产生的回滚日志

Read View 可读视图

组成 [未提交事务数组],最大的事务 id

可读视图判断规定

生成一致性视图规定 read-view

由执行时所有未提交事务的 id 数组(数组里最小的 trx_id 为 min_id)和已创立的事务 id(max_id)组成,查问的数据后果依据生成 的 read-view 做比照失去快照的后果

版本链比对判断规定

  • 如果落在绿色局部(trx_id<min_id), 示意这个版本是已提交事务生成的,这个事务是可见的
  • 如果落在黄色局部(min_id<=trx_id<=max_id), 分两种状况解决

    a. 若 row 的 trx_id 在数组中,示意这个事务是由还没提交的事务生成的,不可见,以后本人的事务是可见的

    b. 若 row 的 trx_id 不在数组中,示意这个事务是曾经提交的事务生成的,可见

  • 如果落在红色局部 (trx_id>max_id),示意这个版本是由未来启动的事务创立的,必定不可见

对于删除的状况能够认为是 update 的非凡状况,delete 数据的时候会将版本上最新的数据复制一份,而后将 trx_id 批改成删除操作的 trx_id,同时将该条记录的头信息(record header)里的(deleted_flag)标记位写上 true,示意以后记录曾经被删除,在查问时依照下面的规定查到对应的记录,如果 deleted_flag 标记位为 true,意味着数据曾经被删除,则不会被返回。

举例说明 MVCC 实现原理

表阐明

  • t 事务操作表,演示表,undolog 日志演示操作表
  • t1 , 辅助表,生成事务 id

隔离级别

可反复读

验证

  • 查看数据库隔离级别(只有可反复读和读提交下 MVCC 无效)

    在 RR 级别下的某个事务对某条记录的第一次快照读会创立一个快照及 read-view,将以后零碎沉闷的其它事务记录起来,尔后在调用快照读的时候还是应用的同一个 read-view,所以只有以后事务在其它事务更新提交之前应用快照读,那么之后的快照读都是对立个 read-view,所以对之后的批改不可见。

    在 RR 级别下,快照读生成 read-view 时,read-view 会记录此时所有其它事务的快照,这些事务对与以后事务都是不可见的,而早于 read-view 创立的事务都是可见的

    而在 RC 级别下,事务中每次都会生成一个新的 read-view 和快照,这就是咱们在 RC 级别下能够看到别的事务提交的更新的起因

    总之就是在 RC 级别下,每个事务都会获取最新的 read-view;而在 RR 级别下,则是同一个事物的第一个 selete 才会创立快照,之后的快照读都是第一次创立的 read-view,都是同一个 read-view

  • 上面为不同时刻不同事务时序图

    transaction100,200,300 为三个更新事务

    select1,2 为两个读取事务

    Transaction 100 Transaction 200 Transaction 300 select 1 select 2
    begin; begin; begin; begin; begin;
    update t1 set t1col=’t1colval’ where id = ‘1’;(辅助表 t1 中更新数据,生成一个事务 ID100)
    update t1 set t1col=’t1colval200′ where id = ‘2’;(辅助表 t1 生成事务 ID200)
    update t set name = ‘zuiyu300’ where id = ‘1’ ;(第一次更新数据)
    commit;
    select name from t where id = ‘1’ ;(第一次读,创立 readview[100,200] 300) 此时读出来的后果是 name=zuiyu300
    update t set name=’zuiyu100′ where id = ‘1’;
    Update t set name =’zuiyu101′ where id = ‘1’;
    select name from t where id = ‘1’; (第二次读,持续应用第一次创立的 readview[100,200] 300) 此时读出来的后果是 name=zuiyu300
    commit;
    update t set name=’zuiyu200′ where id = ‘1’;
    update t set name=’zuiyu201′ where id = ‘1’;
    select name from t where id = ‘1’; (第三次读,持续应用第一次创立的 readview[100,200] 300) 此时读出来的后果是 name=zuiyu300 select name from t where id = ‘1’;(此时会生成一个 readview [200],300), 此时后果 name=zuiyu101
    commit; commit; commit;
  • 第一次读取时

    生成的 read view [100,200]300,min_id=100,max_id=300

    版本链信息如下:

    查找规定为

    1、第一条记录 trx_id=300,落在两头区域

    2、300 不在获取事务数组中,所以可见,返回 name=zuiyu300

  • 第二次读取时

    以后隔离级别为可反复度,应用第一次读取时生成的 read view,生成的 read view [100,200]300,min_id=100,max_id=300,

    版本链信息如下

    查找规定

    1、第一条记录 trx_id=100,落在两头黄色区域

    2、事务 id100 在沉闷事务数组中,表明不可见,持续往下找

    3、第二条记录 trx_id=100,同比不可见

    4、第三条记录 trx_id=300,落在两头区域,不在沉闷事务数组,可见,返回 name=zuiyu300

  • 第三次读取时

    以后隔离级别为可反复度,应用第一次读取时生成的 read view,生成的 read view [100,200]300,min_id=100,max_id=300

    版本链信息如下

    查找规定

    1、第一条记录 trx_id=200,落在两头黄色区域,200 在沉闷事务数组中,不可见

    2、第二条记录 trx_id=200,不可见

    3、第三条记录 trx_id=100,落在两头黄色区域,100 在沉闷事务数组中,不可见

    4、第四条记录 trx_id=100,不可见

    5、第五条记录 trx_id=300,落在两头黄色区域,不在沉闷事务数组中,可见返回 name=zuiyu300

  • select 2 事务读取时

    生成的 read view [200],300,min_id=200,max_id=300

    此时的沉闷事务只有事务 id 为 200 的,以后的版本链信息如下:

    查找规定为

    1、从上往下,第一条记录 trx_id=200,在沉闷事务数组中,不可见

    2、第二条记录 trx_id=200,不可见

    3、第三条记录 trx_id=100,100<min_id, 所以事务可见,返回后果 name=zuiyu101

总结

可反复读隔离级别下,读取的历史版本数据,依据 UndoLog 版本链中 trx_id 在判断规定中比拟,获取符合条件的数据返回

扫码关注,回复【面试】获取面试宝典

退出移动版