MVCC

发布时间 2023-09-30 21:27:21作者: lmcool-

你解释一下MVCC?

mvcc的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,

它的底层实现主要是依赖了数据库中的三个部分,隐藏字段,undo log日志和readView读视图

隐藏字段是指:在mysql中给每个表都设置了隐藏字段,有一个是最近修改事务的id,记录每一次操作的事务id,是自增的;另一个是回滚指针,指向上一个版本的事务版本记录地址;

undo log主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过回滚指针形成一个链表,链表头部就是最新修改的旧记录,尾部是最早修改的旧记录

readView读视图解决的是一个事务查询选择版本的问题,内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。RC隔离级别下,每一次执行快照读时生成ReadView,RR隔离级别仅在事务中第一次执行快照读时生成读视图,后续复用该读视图

MVCC

多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突

多个事物并发的情况下到底该访问哪个版本

底层实现

  • 隐藏字段:

    • trx_id(事务id),记录每一次操作的事务id,是自增的
    • roll_pointer(回滚指针),指向上一个版本的事务版本记录地址
    • row_id,隐藏主键
  • undo log:

    • 回滚日志,存储老版本数据
    • 版本链:多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll pointer指针形成一个链表
  • readView解决的是一个事务查询选择版本的问题

    • 根据readView的匹配规则和当前的一些事务id判断该访问那个版本的数据

    • 不同的隔离级别快照读是不一样的,最终的访问的结果不一样

      • RC:每一次执行快照读时生成ReadView
      • RR:仅在事务中第一次执行快照读时生成ReadView,后续复用

undo log

回滚日志,在insert、update、delete时产生的便于数据回滚的日志

insert产生的undo log只在回滚时需要,事物提交后可立即被删除

update、delete产生的日志不仅在回滚时需要,MVCC版本访问也需要,不会被立即删除

不同事物或相同事物对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链,链表头部是最新的旧记录,链表尾部是最早的旧记录

ReadView

读视图,是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事物未提交的id

其中

  • Read Committed:RC隔离级别下每次select都生成一个快照读
  • Repeatable Read:RR隔离级别下,开启事物后的第一个select才是快照读

ReadView包含四个核心字段:

字段 含义
m_ids 当前活跃的事务ID集合
min_trx_id 最小活跃事务ID
max_trx_id 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
creator_trx_id ReadView创建者的事务ID

版本链数据访问规则

trx_id: 代表是当前事务ID。

  1. trx_id == creator_trx_id?---->可以访问该版本--------->说明数据是当前这个事务更改的。
  2. trx_id < min_trx_id?---->可以访问该版本--------->成立,说明数据已经提交了。
  3. trx_id >max_trx_id?---->不可以访问该版本--------->成立,说明该事务是在ReadView生成后才开启。
  4. min_trx_id <= trx_id <= max_trx_id? ---->如果trx_id不在m_ids中是可以访问该版本的---->成立,说明数据已经提交。

一个一个比,有一个成立就可以读到

不同隔离级别下,生成ReadView的时机不同

  • RC隔离级别下,在事物中每一次执行快照读时生成ReadView

  • RR隔离级别下,记载事物中第一次执行快照读时生成ReadView,后续复用该ReadView

当前读

读取的是记录的最新版本,读取时还要保证其他并发事物不能修改当前记录,会对读取的记录进行加锁

一般的日常操作select(共享锁)、update、insert、delete(排他锁)都是一种当前读

快照读

读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读

简单的select不加锁就是快照读