mysql中,可重复读是怎么实现的?

2021-03-01 19:55发布

4条回答
瑶仙女呀
2021-03-05 17:01

通过一致性视图和多版本并发控制(MVCC)实现。

MVCC就是一种乐观锁的实现方式,而且是一种很常用的乐观锁实现方式。

所谓多版本,就是一行记录在数据库中存储了多个版本,每个版本以事务ID作为版本号。InnoDB 里面每个事务有一个唯一的事务 ID,是在事务开始的时候向InnoDB的事务系统申请的,并且按照申请顺序严格递增的。假如一行记录被多个事务更新,那么,就会产生多个版本的记录。

以某一行数据作为例子:



经过两次事务的操作,value从22变成了19,同时,保留了三个事务id,15、25、30。

在每个记录多版本的基础上,需要利用“一致性视图”,来做版本的可见性判断。

这里,我们要区分MySQL里面的两个”视图”概念:

  • 一个是view,通过语法create view … 实现,主要创建一个虚拟表,用来执行查询语句。

  • 一个是InnoDB用来实现mvcc的一致性视图(consistent read view),纯逻辑概念,没有物理结构,定义了在事务期间,你能看到哪些版本的数据。

我们全文提到的“视图”都是第二种,主要是支持InnoDB在“读已提交”和“可重复读”级别的并发访问问题。

  • “读未提及”级别下,没有一致性视图

  • “读已提交”级别下,会在 每个SQL开始执行的时候 创建一致性视图

  • “可重复读”级别下,会在 每个事务开始的时候 创建一致性视图

  • “串行化”级别下,直接通过加锁避免并发问题

下面,我们简单介绍一下创建一致性视图的逻辑。

以“可重复读”级别为例。

  • 当一个事务开启的时候,会向系统申请一个新事务id

  • 此时,可能还有多个正在进行的其他事务没有提交,因此在瞬时时刻,是有多个活跃的未提交事务id

  • 将这些未提交的事务id组成一个数组,数组里面最小的事务id记录为低水位,当前系统创建过的事务id的最大值+1记录为高水位

  • 这个数组array 和 高水位,就组成了“一致性视图”。

有了一致性视图后,我们就可以判断一行数据的多版本可见性了,无论是“读已提交”还是“可重复读”级别,可见性判断规则是一样的,区别在于创建快照(一致性视图)的时间。

在当前事务中,读取其他某一行的记录,对其中的版本号的可见性判断有五种情况(建议自己跟着捋一捋,挺重要的):

  • 如果版本号小于“低水位”,说明事务已经提交,那肯定 可见;

  • 如果版本号大于“高水位”,说明这行数据的这个事务id版本是在快照后产生的,那肯定 不可见;

  • 如果版本号在事务数组array中,说明这个事务还没提交,所以 不可见;

  • 如果版本号不在事务数组array中,且低于高水位,说明这个事务已经提交,所以 可见;

  • 当然,无论什么时候,自己的事务id中的任何变化,都是可见的

可以看看下面这个例子,更容易理解。

系统创建过的事务id:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
事务A启动,拍个快照
此时未提交的事务id有:7,8,9
一致性视图:数组array[7,8,9] + 高水位16(15+1)

对于任意一行数据的可见性判断如下:

  • 小于7的,可见

  • 大于16的,说明是快照后产生的,不可见

  • 10-15,不在数组array中,说明已经提交了,可见

  • 7,8,9在array中,说明未提交,不可见

两个重要结论:

  • InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。

  • MVCC的实现,就是根据当前事务的事务id为依据创建“一致性视图”,利用一致性视图来判断数据版本的可见性。

 0人赞  添加讨论(0)举报

 

大大泡泡糖 - 你小时候 经常吃大大泡泡糖吗

3楼-- · 1天前

通过一致性视图和多版本并发控制(MVCC)实现。

MVCC就是一种乐观锁的实现方式,而且是一种很常用的乐观锁实现方式。

所谓多版本,就是一行记录在数据库中存储了多个版本,每个版本以事务ID作为版本号。InnoDB 里面每个事务有一个唯一的事务 ID,是在事务开始的时候向InnoDB的事务系统申请的,并且按照申请顺序严格递增的。假如一行记录被多个事务更新,那么,就会产生多个版本的记录。

以某一行数据作为例子:



经过两次事务的操作,value从22变成了19,同时,保留了三个事务id,15、25、30。

在每个记录多版本的基础上,需要利用“一致性视图”,来做版本的可见性判断。

这里,我们要区分MySQL里面的两个”视图”概念:

  • 一个是view,通过语法create view … 实现,主要创建一个虚拟表,用来执行查询语句。

  • 一个是InnoDB用来实现mvcc的一致性视图(consistent read view),纯逻辑概念,没有物理结构,定义了在事务期间,你能看到哪些版本的数据。

我们全文提到的“视图”都是第二种,主要是支持InnoDB在“读已提交”和“可重复读”级别的并发访问问题。

  • “读未提及”级别下,没有一致性视图

  • “读已提交”级别下,会在 每个SQL开始执行的时候 创建一致性视图

  • “可重复读”级别下,会在 每个事务开始的时候 创建一致性视图

  • “串行化”级别下,直接通过加锁避免并发问题

下面,我们简单介绍一下创建一致性视图的逻辑。

以“可重复读”级别为例。

  • 当一个事务开启的时候,会向系统申请一个新事务id

  • 此时,可能还有多个正在进行的其他事务没有提交,因此在瞬时时刻,是有多个活跃的未提交事务id

  • 将这些未提交的事务id组成一个数组,数组里面最小的事务id记录为低水位,当前系统创建过的事务id的最大值+1记录为高水位

  • 这个数组array 和 高水位,就组成了“一致性视图”。

有了一致性视图后,我们就可以判断一行数据的多版本可见性了,无论是“读已提交”还是“可重复读”级别,可见性判断规则是一样的,区别在于创建快照(一致性视图)的时间。

在当前事务中,读取其他某一行的记录,对其中的版本号的可见性判断有五种情况(建议自己跟着捋一捋,挺重要的):

  • 如果版本号小于“低水位”,说明事务已经提交,那肯定 可见;

  • 如果版本号大于“高水位”,说明这行数据的这个事务id版本是在快照后产生的,那肯定 不可见;

  • 如果版本号在事务数组array中,说明这个事务还没提交,所以 不可见;

  • 如果版本号不在事务数组array中,且低于高水位,说明这个事务已经提交,所以 可见;

  • 当然,无论什么时候,自己的事务id中的任何变化,都是可见的

可以看看下面这个例子,更容易理解。

系统创建过的事务id:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
事务A启动,拍个快照
此时未提交的事务id有:7,8,9
一致性视图:数组array[7,8,9] + 高水位16(15+1)

对于任意一行数据的可见性判断如下:

  • 小于7的,可见

  • 大于16的,说明是快照后产生的,不可见

  • 10-15,不在数组array中,说明已经提交了,可见

  • 7,8,9在array中,说明未提交,不可见

两个重要结论:

  • InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。

  • MVCC的实现,就是根据当前事务的事务id为依据创建“一致性视图”,利用一致性视图来判断数据版本的可见性。


 0人赞  添加讨论(0)

您可以邀请下面用户,快速获得回答

小猪仔

在话题大数据下有 79 个回答

小优聊IT

在话题大数据下有 1 个回答

雨陵西

在话题大数据下有 13 个回答

挺好的

在话题大数据下有 4 个回答

玄月

在话题大数据下有 7 个回答

早安

在话题大数据下有 1 个回答

IT-小敏同学

在话题大数据下有 13 个回答

热爱学习群众

在话题大数据下有 5 个回答

汤圆和辣条

在话题大数据下有 24 个回答

像风没有归宿

在话题大数据下有 11 个回答

779

在话题大数据下有 5 个回答

霸气的名字

在话题大数据下有 25 个回答

小绵羊吖

在话题大数据下有 5 个回答

无所不能的——我

在话题大数据下有 1 个回答

林夕雨

在话题大数据下有 4 个回答

水默

在话题大数据下有 35 个回答

爱梦

在话题大数据下有 21 个回答

大冬瓜

在话题大数据下有 7 个回答

IT学习

在话题大数据下有 10 个回答

呼呼哈小童鞋

在话题大数据下有 10 个回答

加载更多答主

一周热门更多>

相关问答


一周热门 更多>