MySql,MVCC实现及其机制,快照读在RC,RR下的区别说明

 更新时间:2024年04月08日 08:50:35   作者:今吴霜.  
这篇文章主要介绍了MySql,MVCC实现及其机制,快照读在RC,RR下的区别说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一、什么是MVCC

多版本并发控制

Multiversion Concurrency Control

大部分的MySQL的存储 引擎,比如InnoDB,Falcon,以及PBXT并不是简简单单的使用行锁机制。它们都使用了行锁结合一种提高并发的技术,被称为MVCC(多版本并 发控制)。MVCC并不单单应用在MySQL中,其他的数据库如Oracle,PostgreSQL,以及其他数据库也使用这个技术。 

MVCC避免了许多需要加锁的情形以及降低消耗。这取决于它实现的方式,它允许非阻塞读取,在写的操作的时候阻塞必要的记录

MVCC保存了某一时刻数据的一个快照。意思就是无论事物运行了多久,它们都能看到一致的数据。也就是说在相同的时间下,不同的事物看相同表的数据是不同的。如果你从来没有这方面的经验,可能说这些有点令人困惑。但是在以后这个会很容易理解和熟悉的。

每个存储引擎实现MVCC方式都是不同的。有许多种包含了乐观(optimistic)和悲观(pessimistic)的并发控制。我们用简单的InnoDb的行为来举例说明MVCC工作方式。

InnoDB实现MVCC的方法是,它存储了每一行的两个额外的隐藏字段,这两个隐藏字段分别记录了行的创建的时间和删除的时间。在每个事件发生的时 候,每行存储版本号,而不是存储事件实际发生的时间。每次事物的开始这个版本号都会增加。自记录时间开始,每个事物都会保存记录的系统版本号。依照事物的 版本来检查每行的版本号。在事物隔离级别为可重复读的情况下,来看看怎样应用它。

SELECT

  • InnoDB检查每行,要确定它符合两个标准。
  • InnoDB必须知道行的版本号,这个行的版本号至少要和事物版本号一样的老。(也就是是说它的版本号可能少于或者和事物版本号相同)。这个既能确定事物开始之前行是存在的,也能确定事物创建或修改了这行。
  • 行的删除操作的版本一定是未定义的或者大于事物的版本号。确定了事物开始之前,行没有被删除。
  • 符合了以上两点。会返回查询结果。

INSERT

  • InnoDB记录了当前新增行的系统版本号。

DELETE

  • InnoDB记录的删除行的系统版本号作为行的删除ID。

UPDATE

  • InnoDB复制了一行。这个新行的版本号使用了系统版本号。它也把系统版本号作为了删除行的版本。

所有其他记录的结果保存是,从未获得锁的查询。这样它们查询的数据就会尽可能的快。要确定查询行要遵循这些标准。缺点是存储引擎要为每一行存储更多的数据,检查行的时候要做更多的处理以及其他内部的一些操作。

MVCC只能在可重复读和可提交读的隔离级别下生效。不可提交读不能使用它的原因是不能读取符合事物版本的行版本。它们总是读取最新的行版本。可序列化不能使用MVCC的原因是,它总是要锁定行。

下面的表说明了在MySQL中不同锁的模式以及并发级别。

在这里插入图片描述

我们在操作数据库的时候总是这四大类 读读 读写 写读 写写,读读肯定是没有任务数据问题的,但对事物有了解的同学就会知道,读写、写写操作很容易就会导致数据不一致。

在此之前解决这类问题的常用方式就是 加锁,听名字就知道这是个很复杂、很耗性能的操作,所以大神们不满足这个操作,从而在MySQL里面实现了MVCC。

MVCC并不是MySQL独有的,它是一个理念,百度百科解释如下:

Multi-Version Concurrency Control 多版本并发控制,MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程语言中实现事务内存。

MVCC里面有一些关键词,理解这些关键词,你就明白了什么是MVCC。MVCC是解决读写、写读导致数据不一致的问题,写写问题还是需要加锁来解决。

所以我们可以使用 MVCC + 锁(乐观锁/悲观锁)来解决全部的问题。

二、当前读、快照读

当前读就是读取最新的数据,为了保证读取的是最新且准确的数据,所以它在读取的时候会加锁,防止其它事物操作。

快照读是不加锁的方式,当一个事物要操作数据库的时候,会在这个事物的基础上形成一个快照,其它的操作就读取这个快照。

MVCC就是基于快照读来实现的,在MySQL里面的快照读是基于这样几个关键点来实现的

  • 三个隐藏参数 (DB_ROW_ID 隐藏主键id、DB_ROLL_PTR 回滚指针、DB_TRX_ID 事物id)
  • undo log 日志
  • read view

三、隐藏字段

假如我们有一张表,里面有两个字段,name、age,但实际上我们表里的数据是这样的

在这里插入图片描述

3-1、隐藏主键

6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引

聚簇索引:数据存储和索引是存在一起的,逻辑上和物理上都是一起的,一个表只能有一个聚簇索引。

注:理解聚簇索引可以很好的理解MySQL的索引规则,感兴趣的可以看看这个 MySQL索引详解

3-2、事物id

记录这条记录最后一次操作的事物id

3-3、回滚指针

回滚指针,指向这条记录的上一个版本(存储于rollback segment里),用于配合下面的 undo log。

四、undo log

undo log 日志分为两种

(1)、 insert undo log 数据库在插入数据的时候产生,只有在当前事物回滚的时候才有用,所以在当前事物结束的时候它就没用了,就会被删除。

(2)、 update undo log 数据库在更新、删除的时候产生,除了当前事物会使用,在快照读的时候也会使用,所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除。

五、Read View

什么是读视图呢?数据库的操作都是多个事物同时进行的,有读有写。假如当前有两个事物,A事物读取,B事物正在更新数据。

在A事物开始的时候,就形成当前数据库的一个快照,记录并维护系统当前活跃事务的ID。read view 主要是用来做可见性判断的,它会判断每条记录的的数据,这条数据可能是真实的数据,也可能是undo log 中的数据。

read view 用一个可见性的算法,来判断当前是读取真实的数据,还是undo log的数据。这里可以简单理解read view 内部维护了一个事物id列表,里面有最大值和最小值,可以判断其它事物的id是否在这个可见范围内。

N、其它

N-1、快照读在RC和RR下的区别

  • RC (read-committed)读已提交, 可能会导致 不可重复读、幻读
  • RR (repeatable-read)可重复读,可能会导致 不可重复读

幻读 : 事物A查询数据库查询出来了20条数据,然后事物B删除了2条数据,这时候事物A再去查询发现只有18条了,从而产生了幻觉。

我们知道在RR级别下面不会产生幻读,之所以不会产生幻读,是快照读在RC和RR下的生成的策略不一样。

RC隔离级别下,是每个快照读都会生成并获取最新的Read View;而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View。

MySQL/InnoDB定义的4种隔离级别:

Read Uncommited

  • 可以读取未提交记录。

Read Committed (RC)

  • 针对当前读,RC隔离级别保证对读取到的记录加锁 (记录锁),存在幻读现象

Repeatable Read (RR)(默认)

  • 针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。

Serializable

  • 从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。
  • Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • MySQL并发更新数据时的处理方法

    MySQL并发更新数据时的处理方法

    在后端开发中我们不可避免的会遇见MySQL数据并发更新的情况,作为一名后端研发,如何解决这类问题也是必须要知道的,同时这也是面试中经常考察的知识点。
    2019-05-05
  • linux下mysql乱码问题的解决方案

    linux下mysql乱码问题的解决方案

    今天小编就为大家分享一篇关于linux下mysql乱码问题的解决方案,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • 重装MySQL最后一步失败的完美解决方案(经验总结)

    重装MySQL最后一步失败的完美解决方案(经验总结)

    使用MySQL都有过重装的经历,要是重装MySQL基本都是在最后一步通不过,究竟是什么原因呢?下面是我总结的一点经验,都是血的教训
    2014-06-06
  • mysql视图之创建可更新视图的方法详解

    mysql视图之创建可更新视图的方法详解

    这篇文章主要介绍了mysql视图之创建可更新视图的方法,结合实例形式分析了mysql可更新视图的具体创建、使用方法及相关操作注意事项,需要的朋友可以参考下
    2019-12-12
  • mysql多表join时候update更新数据的方法

    mysql多表join时候update更新数据的方法

    如果item表的name字段为''就用resource_library 表的resource_name字段前面加上字符串Review更新它,他们的关联关系在表resource_review_link中。
    2011-03-03
  • 详解MySQL substring() 字符串截取函数

    详解MySQL substring() 字符串截取函数

    MySQL 查询数据有时候需要对数据项进行日期格式化或截取特定部分的操作,当需要对字符串进行截取加工时用到了 substring() 函数,这篇文章主要介绍了MySQL substring() 字符串截取函数,需要的朋友可以参考下
    2022-07-07
  • MySQL主从状态检查的实现

    MySQL主从状态检查的实现

    这篇文章主要介绍了MySQL主从状态检查的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • 在OneProxy的基础上实行MySQL读写分离与负载均衡

    在OneProxy的基础上实行MySQL读写分离与负载均衡

    基于Libevent机制实现,单个实例可以实现25万的SQL转发能力,用一个OneProxy节点可以带动整个MySQL集群,为业务发展贡献一份力量,下面由小编来为大家简单说说
    2019-05-05
  • mysql5.7 新增的json字段类型用法实例分析

    mysql5.7 新增的json字段类型用法实例分析

    这篇文章主要介绍了mysql5.7 新增的json字段类型用法,结合实例形式分析了mysql5.7 新增的json字段类型具体功能、使用方法及操作注意事项,需要的朋友可以参考下
    2020-02-02
  • Linux下安装MySQL8.0.11的教程

    Linux下安装MySQL8.0.11的教程

    这篇文章主要介绍了Linux下安装MySQL8.0.11的教程,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12

最新评论