Mysql-MVCC读写并发控制理解分析

1. 概念

MVCC(Multi-Version Concurrent Control)多版本并发控制,在Mysql Innodb中主要是用于提高数据库并发能力,做到存在读写冲突时,也能不加锁非阻塞并发读

2. 当前读、快照读

类型概念
当前读当前读即为每次读取的数据均为最新数据,如select … lock in share mode(共享锁)、select … for update、update、delete(排它锁)等均为当前读,因为他们读取的均为记录的最新数据,且在读取时会对该行数据进行加锁。
快照读不加锁的select为快照读。此时的数据库隔离级别必须是非串行级别,否则会退化为当前读。快照读基于Read View(可读视图)实现,所以它读取到的数据不一定是当前最新数据,而可能是历史数据。

3. 工作原理

MVCC工作原理主要依赖:

  1. 数据行中的三个隐藏字段DB_TX_ID、DB_ROLL_PTR、DB_ROW_ID
  2. Undo Log
  3. Read View(可读视图,见下一小节)

MVCC仅在隔离级别:读已提交、不可重复读下发挥作用。

3.1 隐藏字段图解

在这里插入图片描述
特别说明回滚指针DB_ROLL_PTR的应用:
在这里插入图片描述

3.2 Read View可读视图

Read View概念

Read View是事务在进行快照读时产生的读视图(即select时生成)。

Read View中存在以下三个关键变量:
在这里插入图片描述
这里需要说明的是,事务ID是自动递增的,也就是说下一次产生的事务比上一次产生的事务ID要来的大,可按平时设计的表中的主键ID自动递增理解。图中的low_limit_id表示尚未分配的事务ID,但是下一个产生的事务的ID就是他。

举例说明
在这里插入图片描述

Read View判断条件

Read View判断某行数据对当前事务是否可见,按以下步骤进行判断:

1若数据行的事务ID[DB_TX_ID] < = 集合最小事务ID[up_limit_id],则表示该数据行在当前事务开启前(等于的情况则表示是当前事务修改的记录,肯定可见)就已经提交(产生),对当前事务可见
2若数据行的事务ID[DB_TX_ID] > = 下一事务ID[low_limit_id],则表示该数据行是当前事务开启之后产生,则对当前事务不可见
3如果1,2条件均不满足,则判断集合最小事务ID[up_limit_id]<=数据行的事务ID <= 下一事务ID[low_limit_id]范围内,如果满足,则需要判断数据行事务ID是否存在集合事务ID[trx_list]中,如果存在,则表示产生该行数据的事务扔处于活跃状态,事务并未提交,该行数据对当前事务不可见。否则表示该数据行已经提交事务,对当前事务可见
4如果该数据行对当前事务不可见,则顺着版本链向下遍历,重复1,2,3,4步骤直到找到对应的版本数据行,若未找到,则SELECT查询结果集为空

前面说过 MVCC在隔离级别 读已提交/可重复读 两个隔离级别下才生效
同时还有以下区别:
读已提交:每次SELECT时均产生一个最新的Read View
可重复读:每次SELECT均复用第一次SELECT产生的Read View

Read View在【读已提交】隔离级别下的使用

理解了上面的图示后,就可以理解两个事务共同存在时,A事务可以读取到B事务已提交的数据:
(当前隔离级别为 读已提交)

事务1事务2
操作1事务开启:BEGIN事务开启:BEGIN
操作2SELECT
操作3UPDATE
操作4COMMIT
操作5SELECT

问:在读已提交的隔离级别下,事务1操作2和操作5的SELECT结果是否一致?
答案是明显的,事务1操作5的SELECT是事务2更新后的结果,所以两次SELECT结果不一致。

解释
在事务1操作2时,进行了一次快照读SELECT,此时产生一个Read View,如图(包含了select的数据行在数据库中的形式):
在这里插入图片描述

经事务2执行Update并Commit后,数据行发生如下变化
在这里插入图片描述
此时事务1再次SELECT(操作5),再次生成Read View结果如下:
在这里插入图片描述
根据Read View判断条件3可知,事务ID为2的数据行对事务1可见。

若在事务2进行Update后,并未Commit,而此时事务1进行SELECT,则Read View结果如下:
在这里插入图片描述
此时根据数据行事务ID为2进行判断,事务2仍在活跃列表[trx_list]中,表示当前事务并未提交,则该行数据行对当前事务不可见。

Read View在【可重复读】隔离级别下的使用

在事务1第一次SELECT(操作1)时,生成的Read View结果如下:
在这里插入图片描述
尽管经事务2执行Update并Commit后,数据行变为以下内容:
在这里插入图片描述
但是当事务1执行第二次SELECT(操作5)时,可重复读隔离级别多次SELECT均复用第一次生成的Read View结果。则此时的Read View中活跃列表[trx_list]中仍存在事务2,所以事务ID为2的数据行对事务1不可见,则顺着版本链向下遍历,找到事务ID为0的数据行,该数据行满足Read View判断条件1,所以对事务1可见,SELECT查询结果集中包含该行数据行。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值