• MVCC的执行原理


    MVCC简介

    MVCC(Multi-Version Concurrency Control)是一种并发控制机制,用于解决数据库并发访问中,数据一致性问题。它通过在读写操作期间保存多个数据版本,以提供并发事务间的隔离性,从而避免了传统的锁机制所带来的资源争用和阻塞问题。

    所谓的一致性问题,就是在并发事务执行时,应该看到那些数据和不应该看到那些数据。

    事务的隔离级别

    为了解决并发事务存在的脏读、不可重复读、幻读等问题,数据库大叔设计了四种隔离级别。

    • 读未提交(Read Uncommitted):读未提交隔离级别,只限制了两个数据不能同时修改,但是修改数据的时候,即使事务未提交,都是可以被别的事务读取到的,这级别的事务隔离有脏读、重复读、幻读的问题;
    • 读已提交(Read Committed):读已提交隔离级别,当前事务只能读取到其他事务提交的数据,所以这种事务的隔离级别解决了脏读问题,但还是会存在重复读、幻读问题;
    • 可重复读(Repeatable Read):可重复读隔离级别,限制了读取数据的时候,不可以进行修改,所以解决了不可重复读的问题,但是读取范围数据的时候,是可以插入数据,所以还会存在幻读问题;
    • 串行化(Serializable ):事务最高的隔离级别,在该级别下,所有事务都是进行串行化顺序执行的。可以避免脏读、不可重复读与幻读所有并发问题。但是这种事务隔离级别下,事务执行很耗性能。

    MVCC作用

    数据库是通过加锁,来实现事务的隔离性的。加锁确实好使,可以保证隔离性。比如串行化隔离级别就是加锁实现的。从而避免了脏读、不可重复读、幻读的问题。但是频繁的加锁,导致读数据时,没办法修改,修改数据时,没办法读取,大大降低了数据库性能。

    那么,如何解决加锁后的性能问题的?

    答案就是:MVCC多版本并发控制! 它实现读取数据不用加锁,可以让读取数据同时修改。修改数据时同时可读取。
    四大隔离级别中的 读已提交(RC)可重复读(RR) 隔离级别就是通过MVCC来实现的。

    当前读和快照读

    快照读:是指在一个事务中,读取的数据版本是在事务开始时已经存在的数据版本,而不是最新的数据版本。这种读取方式提供了事务在执行期间看到的数据视图的一致性,select 查询就是快照读。

    当前读:是指在事务中读取最新的数据版本,以下几种操作都是快照读:

    • select lock in share mode(共享锁)
    • select for update(排他锁)
    • update(排他锁)
    • insert(排他锁)
    • delete(排他锁)

    MVCC实现原理

    MVCC 主要是依靠以下三部分实现的:

    • Undo Log
    • Undo Log 版本链
    • Read View(读视图或者叫一致性视图)

    Undo Log

    Undo Log 主要是用于数据库中事务回滚的,但在 MVCC 机制中也发挥着重要的作用。

    Undo Log 版本链

    Undo Log 版本链是指在每个数据对象上维护的 Undo Log 记录链表。每张表都会有与之相对应的 Undo Log 版本链,用于记录修改前的数据信息(以方便数据进行回滚)。
    在这里插入图片描述

    Read View

    Read View(读视图)用于管理事务之间数据可见性的一种机制。Read View 在特定时刻为事务创建的一个快照,该快照包含了在该时刻所有未提交事务的事务标识符,以及其他一些辅助信息。
    在 Read View 中包含了以下 4 个主要的字段:

    • m_ids:当前活跃的事务编号集合。
    • min_trx_id:最小活跃事务编号。
    • max_trx_id:预分配的事务编号,当前最大事务编号+1。
    • creator_trx_id:ReadView 创建者的事务编号。

    解释:
    活跃的事务编号:指的是已经创建,但未commit的事务,即处理中的事务id。

    RC 级别中,每次快照读都会生成一个全新的 Read View,而 RR 级别中同一个事务会复用一个 Read View。
    有了 Read View 和 Undo Log 链之后,并发事务在查询时就知道要读取那些数据了。

    判断方法

    判断方法是根据 Read View 中的 4 个重要字段,先去 Undo Log 中最新的数据行进行比对,如果满足下面 Read View 的判断条件,则返回当前行的数据,如果不满足则继续查找 Undo Log 的下一行数据,直到找到满足的条件的数据为止,如果查询完没有满足条件的数据,则返回 NULL。

    判断规则

    在这里插入图片描述

    • trx_id==creator_trx_id:先将 Undo Log 最新数据行中的 trx_id 和 ReadView 中的 creator_trx_id 进行对比,如果他们两个值相同,则说明是在同一个事务中执行,那么直接返回当前 Undo Log 的数据行即可,如果不相等,则继续下面流程。
    • trx_id
    • trx_id>max_trx_id:如果 trx_id 如果大于等于 max_trx_id,则说明该行数据比当前操作执行的晚,当前行数据不可见,继续执行后续流程。
    • min_trx_id<=trx_id
    • trx_id 在 m_ids 中:说明事务尚未执行完,该行数据不可被访问。
    • trx_id 未在 m_ids 中:说明事务已经执行完,可以返回该行数据。

对于删除的情况,会将版本链的最新数据复制一份,然后将trx_id修改成删除操作的trx_id,同时会在记录的头信息的标记位(delete_flag)上设置true,用来表示已经删除,在查询时,如果对应记录的delete_flag为true,则表示已经被删除,就不会返回数据。

以上判断规则从 Undo Log 最新的行数据,逐行对比,直到找到匹配的数据,否则查询完未匹配上,则返回 NULL。

小结

  • MVCC 的实现主要依赖读视图 Read View 和 Undo Log 链,通过 Read View 中的 4 个字段,判断要读取 Undo Log 中数据,从而解决了数据库并发访问中,数据一致性的问题。

  • MVCC 主要应用于 InnoDB 引擎中的 RC 事务隔离级别和 RR 隔离级别,其中 RC 隔离级别每次快照读都会生成一个新的 Read View,而 RR 隔离级别只在第一次快照读时生成 Read View,之后会复用 Read View,从而解决了(部分)幻读问题。

  • MVCC是一种用于解决数据库并发问题的乐观锁技术,多版本并发控制通过保存数据在某个时间点的快照来实现。换句话说,读操作不会阻塞写操作,写操作也不会阻塞读操作,以此来提高数据库性能。在每次对数据的操作,都用在undo日志版本链中进行。

  • 相关阅读:
    突破编程_C++_面试(单元测试)
    阿里云数据库RDS有哪些?细数关系型数据库大全
    OpenCV——总结《车牌识别》
    我的git笔记
    spring注入的几种方式(文件配置以及注解方式)
    吐血整理的 Android 性能优化思维导图,让面试官眼前一亮
    使用 python 检测泛洪攻击的案例
    用10元,20元,50元三种币值的纸币凑出1000元,一共有多少种组合(C++实现)三种思路,两种实现
    2022年全球最具技术实力的的智能合约安全审计公司推荐
    【Vue】TypeError: Cannot read properties of undefined (reading ‘xxx‘)
  • 原文地址:https://blog.csdn.net/qq_37896194/article/details/138162855