MySQL InnoDB存储引擎下的MVCC机制

mvcc  多版本并发控制。目的:在并发访问数据库系统的时候来提高读写效率

了解两个概念:

当前读:读取的是数据的最新版本,总是读到最新的数据

快照读:读取的是历史版本的记录。

MVCC的实现主要依赖三部分:**隐藏字段、undo log 和read view**

1.**隐藏字段**

隐藏字段就是每一行记录上都有三个用户看不到的字段:

DB_TRX_ID:最后一次插入/更新该行记录的事务id,并且delete操作在内部被视为更新。

DB_ROW_ID:隐藏主键,如果该表没有主键,则会查找是否有唯一键如果也没有唯一键则会用该id生成聚簇索引。

DB_ROLL_PTR:回滚指针,指向该行的上一个对应的历史记录,这个历史记录是在undo log中的。

2.**undo-log 回滚日志**

回滚日志保存的是数据的历史版本状态,在我们进行增删改之后,方便我们进行回滚的一个日志记录。undo log的两个作用:

​    1.方便事务回滚,将数据恢复到修改前的样子

​    2.另一个是MVCC,读取记录时,如果该记录被其他事务占用或者当前版本对该事务不可见,则可以通过undo log读取之前的版本数据,从而实现非锁定读。

undo log也是保证事务原子性和快照读的基础。

在InnoDB中 undo log分为两种:

​    1.insert undo log:指在insert操作中产生的undo log。因为insert操作的记录只对事务本身可见,对其他事务不可见,所以insert undo log 可以在事务提交之后直接删除

​    2.updat undo log:指在update、delete操作中产生的undo log。该undo log可能需要提供MVCC机制,因此不能在事务提交时就删除。事务提交时会放入undo log链表中,不同或相同事务对同一记录行的一次修改,就会在该undo log中产生一条记录。最终该记录行的undo log会形成一个链表,表头是最新的记录,表尾是最旧的记录。

**3.read view**(快照)

read view 主要用来做可见性判断,里面保存了当前对本事务不可见的其他活跃事务。

m_low_limit_id:下一个将被分配的事务id,目前出现过的最大的事务id+1。大于这个id的数据版本均不可见

m_ids:Read View 创建时其他未提交的活跃事务ID列表。在创建Read view时,将未提交的事务id记录在此列表。后续即使它们修改了记录行的值,对于当前事务也是不可见的。m_ids中不包括当前事务自己和已提交的事务。

m_up_limit_id:活跃事务列表m_ids中最小的事务ID,如果m_ids为空,则为m_low_limit_id。小于这个id的数据版本均不可见。

m_creator_trx_id:创建该Read View的事务ID。

**数据可见性算法:**

在InnoDB存储引擎中,创建一个事务后,没次执行select操作前,都会创建一个Read View(快照)。Read View中的具体内容如上,简单的说就是存储了当前数据库系统中未提交的活跃的事务ID。当我们当前的事务进行select操作时,具体读取到的是哪一个版本的数据呢?这就需要将当前事务ID和该记录行的DB_TRX_ID指针(指向最后一次对该行记录进行更新和插入操作的事务id)以及Read View中的一些变量进行比较。具体比较规则如下:

1.DB_TRX_ID<m_up_limit_id,也就是最新的对该行记录修改/删除操作的事务id,比当前活跃的事务列表中最小的id还要小,说明最新修改该行的事务是在当前事务创建Read view之前就提交了,所以该行记录的值对当前事务可见

2.DB_TRX_ID>=m_low_limit_id,也就是最新修改该行的事务大于等于当前活跃的事务列表中的最大的事务id+1。说明最新修改该行的事务是在当前事务创建Read view之后修改的该行。所以该行记录的值对当前事务不可见,跳到第5步。

3.m_ids为空,说明当前事务创建read view之前,修改该行的事务都提交了,所以该行记录的值对当前事务可见。

4.如果m_up_limit_id<=DB_TRX_ID<m_up_limit_id。说明最新修改该行事务的id在当前事务创建read view的时候,可能处于活跃状态或者已提交状态。这时要遍历m_ids,查找最新修改该行事务的id是否在活跃事务列表中(源码用二分查找,因为是有序的)。

​    4.1能找到,说明当前事务创建read view时,该事务还在活跃状态,所以修改的数据对当前事务不可见,跳到第5步。

​    4.2找不到,说明当前事务创建read view时,该事务已经提交了。修改的数据结果对当前事务可见。

5.这是针对当前行记录对当前事务可见的情况下的操作,不可见的话在该记录行的DB_ROLL_PTR(回滚指针)指向的undo log中取出快照记录,重新从第一步进行比较,直到找到该版本数据对当前事务可见或者返回为空。

**注:**事务的四种隔离级别中MVCC只在读已提交(RC)和可重复读(RR)这两个级别下工作。

在读已提交的隔离级别下,事务每次进行select操作时,都会生成一个新的 Read View,这也是读已提交隔离级别下,有可能会存在不可重复读的情况。

在可重复读的隔离级别下,事务只会在第一次select操作时,生成一个Read View,这就有效避免了不可重复读,但是仍有可能出现幻读的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值