MVCC:多版本并发控制

1. MVCC是什么

  • MVCC(Multi Version Concurrency Control),多版本并发控制;
  • MVCC用于解决读-写并发问题,避免发生脏读、幻读等问题;
  • MVCC通过数据行的多个版本管理实现并发控制;
  • MVCC使InnoDB的事务隔离级别下一致性读操作得到保证,即在查询一些被其他事务正在修改的数据时,不用进入等待,而是直接读取数据被更新之前的值;
  • 不同数据库对MVCC的实现方式可能不同,且MySQL数据库中只有InnoDB引擎支持MVCC;
  • MVCC的实现依赖于:1)行记录的隐藏字段;2)Undo Log;3)Read View;
  • MVCC只针对读已提交和可重复读两种隔离级别起作用;

2. 快照读和当前读

  • MVCC锁解决的读-写冲突问题中,读指快照读;

2.1 快照读

  • 快照读即一致性读,读取的是快照数据,而非当前最新数据;
  • 不显式加锁的SELECT即属于快照读;
  • 快照读可使得即使存在读-写冲突,也可以在不加锁的情况下,实现并发读,提高并发性能;
  • 快照读基于多版本管理控制,有时读到的不一定是最新数据,有可能是之前的历史版本;
  • 快照读的前提是事务隔离级别不是串行化,否则快照读退化为当前读;

2.2 当前读

  • 当前读指读取最新数据,读取时需要保证其他事务不能对数据进行修改,因此需要对数据加锁;
  • 显式加锁的SELECT或对数据进行增删改操作都会执行当前读;
    在这里插入图片描述

3. Read View

  • MVCC通过Read View管理Undo Log中记录的可见性,确定当前事务需要读取记录的对应版本;
  • 记录中含有三个隐藏字段:1)row_id:用于特殊情况下构建聚簇索引;2)trx_id:事务id,表示对该记录进行更新的最近事务ID;3)roll_pointer:回滚指针,用于将记录回滚到指定历史版本;
  • 记录的历史版本通过Undo Log构建,多个事务对于同一记录的修改会以Undo Log的形式保存下来,且这些log会以链表形式(通过记录中的回滚指针连接)存在,如:
    在这里插入图片描述
  • 事务开启之时,会对当前数据库系统生成一个快照,该快照就是Read View,其中维护如:1)产生该Read View的事务ID;2)产生当前Read View时,系统中的活跃事务ID;等信息;
  • Read View的主要作用是在记录对应版本链中确认哪些版本对于当前事务是可见的;
  • 注意MVCC用于解决读-写冲突,只对应于读已提交和可重复读两种隔离级别,因此Read View的具体生成与隔离级别有关:
    1)隔离级别为读已提交时,可解决脏读问题,所以对于每一次的SELECT查询均会生成对应的Read View;
    2)隔离级别为可重复读时,可解决脏读、不可重复读以及幻读问题,所以对于某事务中的多次SELECT查询只会在第一次时生成对应的Read View;

3.1 Read View中含有什么内容

  • creator_trx_id :创建这个 Read View 的事务 ID(只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都默认为0);
  • trx_ids :表示在生成ReadView时当前系统中活跃的读写事务的事务id列表 ;
  • up_limit_id :活跃的事务中最小的事务 ID;
  • low_limit_id:表示生成ReadView时系统中应该分配给下一个事务的 id 值,low_limit_id 是系
    统最大的事务id值

3.2 ReadView的规则

访问某条记录时,通过ReadView,只需要按照下边的步骤判断记录的某个版本是否可见:

  • 如果被访问版本的trx_id属性值与ReadView中的 creator_trx_id相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问;
  • 如果被访问版本的trx_id属性值小于ReadView中的 up_limit_id 值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问;
  • 如果被访问版本的trx_id属性值大于或等于ReadView中的 low_limit_id 值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问;
  • 如果被访问版本的trx_id属性值在ReadView的 up_limit_idlow_limit_id 之间,那就需要判断一下trx_id属性值是不是在 trx_ids 列表中:
    1)如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;
    2)如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问;

4. MVCC整体操作流程

当查询一条记录的时候,系统使用MVCC根据如下步骤进行读取:

  1. 首先获取事务自己的版本号,也就是事务 ID;
  2. 获取 ReadView;
  3. 查询得到的数据,然后与 ReadView 中的事务版本号进行比较;
  4. 如果不符合 ReadView 规则,就需要从 Undo Log 中获取历史快照;
  5. 最后返回符合规则的数据,如果没有找到符合规则的版本,则表示记录不存在;

参考《尚硅谷:康师傅》

猜你喜欢

转载自blog.csdn.net/qq_43665602/article/details/131786957