MongoDB、MySQL、Oracle、PostgreSQL 等事务型数据库都有 mvcc 的概念。

MVCC: 即多版本并发控制,主要是为了提高数据库的读写性能,让数据库在读写的时候不用去加锁。mvcc 主要是处理读请求,这个读指的是快照读,而不是当前读,快照读就是普通的 select 查询。而当前读,其实就是一种悲观锁,要靠加锁实现,比如我们执行 update 或 delete 的时候,你需要先把数据读出来,然后再进行修改操作。比如 select xx for update, 这种排他锁,还有 select xxx lock in share mode 共享锁,这种加锁的方式就是当前读,是需要用锁来保证数据的强一致性。快照读是用 mvcc 实现的,他的目的是读写数据行的时候,不用去竞争锁,提升数据库的并发性能。

数据库的事务有 acid 的特性,原子性用 undo log 实现,持久性是 redo log,而隔离性则是通过加锁和 mvcc 实现。 mysql 事务有 4 中隔离级别: 读未提交,读已提交,可重复读,串行化。一般常用的是读已提交,可重复读这两种。读已提交,可重复读 他们的快照读都是基于 mvcc 实现的。

mvcc 常见的几个概念:(图片来源百度)

(1)undo log

(2)版本链

id = 1 这条记录,经过了多次修改。 修改的历史版本都保存在了 undo log 里。数据库里的每行记录实际上包含一个回滚指针 ( 这是一个隐藏字段 ),指向上一个版本记录,如果你想得到 name=”张三“ 的记录,需要通过版本链多次回滚才行。

(3)Readview 可见性

readview 其实就是一次快照(相当于python 的 一个 class 对象),但是有个问题,当查询 select id=1 的时候,我应该读哪个版本呢,难道总是读最新吗? readview 的作用就是让你知道,你要选择读哪个快照版本。

readview 有一些参数:

m_ids: 表示在生成 Readview 时当前系统中活跃(指还未commit 的事务)的读写事务的 事务id 列表。

min_trx_id: 表示在生成 readview 时当前系统中活跃的读写事务最小的 事务id,也就是 m_ids 中最小的值。

max_trx_id: 表示生成 readview 时系统中应该分配下一个事务的 id 值。

create_trx_id: 表示生成 readview 的事务的 事务id。也就是谁生成了这个 readview。(我自己的事务 id。相当于是 自己记录自己。 )

可能不太直观,举个栗子如下:

eg:当前实例中 show proceeelist 查看活跃的事务列表是 m_ids = [2,3,4, 5] ,那么 min_trx_id=2,max_trx_id=6。

readview 视图如何判断版本链中的哪个版本可用呢?他有4 种判断逻辑

【1】trx_id == create_trx_id: 可以访问这个版本; # trx_id 指的就是如下图中的每条记录的事务 ID。 trx_id == create_trx_id 意味着,这条记录是我自己本身(当前 session)生成的事务(readview),我读取我自己创建的这条记录,当然是可读的。别人不可读是为了阻塞,我自己不可能阻塞我自己,没有意义。

【2】trx_id < min_trx_id:可以访问这个版本。说明,我这个 trx_id 就不是一个活跃的 id ,他已经commit 了 。

【3】trx_id > max_trx_id: 不可以访问这个版本。因为 该 readview 还没有生成。

【4】min_trx_id <= trx_id <= max_trx_id : 如果 trx_id 在 m_ids 中,那么是不可以访问这个版本的,在 m_ids 列表里 说明当前事务是活跃事务。

MVCC 是针对 RC 和 RR 隔离级别的:

RC 和 RR 级别 本质的区别是他俩 生成 readview 的时机不同:

【1】RC 中 以每个 select 的查询为单位(update, delete 的查询也算),每次 select 都会生成一个新的 readview,如果一个事务执行的过程中执行了多次 select,那么事务执行的过程中就要生成多个 readview 。本质是一个事务生成了多了 readview 。 RC 有不可重复读的问题。

【2】RR 生成 readview 是以事务为单位的。比如一个事务有三个 select 语句,但是只会生成一个 readview,后面两个 select 使用的 readview 和 第一个一样,他不会再继续生成 readview,所以在可重复读级别下, readview 是以事务为级别的 ,一个事务只会生成一个 readview。RR 级别就是用这个方法解决了不可重复读的问题。

Eg: 我现在开启了一个事务,包含了两个 select 动作,在执行第一个 select 的时候生成了这个 readview,第一个 select 查询到的是 name=“张三”,那么就算另一个 session 的 update 事务 commit 了,我这个事务的第二个 select 查询用到的依然是 第一个 select 的 readview name = “张三”,第一次生成的 readview 是什么样,之后的这个 readview 就是什么样,直到我这个事务执行完毕。 RR 虽然解决了不可重复的问题,但还是存在 幻读的问题,所以要加锁( 间隙锁 + next key lock )解决幻读的问题。 幻读只是在 RR 级别才会出现的。

我们知道 快照读是通过 mvcc 实现的,当前读都是通过加锁实现的:快照读是如何解决幻读的问题呢?

RR 级别因为事务开始的时候只会生成一分 readview,那么外界再怎么对这个数据进行增加,都对我这个readview 视图没有影响,我读的还是我第一次生成的视图,外部的数据再怎么更新,新增,对于我这个视图都没有影响,这种方式解决了幻读的问题。

当前读是通过 间隙锁 + next key lock 实现,间隙锁是锁住了一段范围。RR 级别默认开启了间隙锁。

理解 MVCC的更多相关文章

  1. 【Mysql】深入理解 MVCC 多版本并发控制

    MVCC MVCC(Multi-Version Concurrency Control),即多版本并发控制.是 innodb 实现事务并发与回滚的重要功能.锁机制可以控制并发操作,但是其系统开销较大, ...

  2. 多版本号并发控制(MVCC)在分布式系统中的应用

    QQ群:289150599 问题 近期项目中遇到了一个分布式系统的并发控制问题.该问题能够抽象为:某分布式系统由一个数据中心D和若干业务处理中心L1,L2 ... Ln组成:D本质上是一个key-va ...

  3. InnoDB MVCC RR隔离级别下的数据可见性总结

    一.背景 熟悉数据库隔离级别的人都知道,在RR(可重复读)隔离级别下,无论何时多次执行相同的SELECT快照读语句,得到的结果集都是完全一样的,即便两次SELECT语句执行期间,其他事务已经改变了该查 ...

  4. HBase并行写机制(mvcc)

    HBase在保证高性能的同时,为用户提供了便于理解的一致性数据模型MVCC (Multiversion Concurrency Control),即多版本并发控制技术,把数据库的行锁与行的多个版本结合 ...

  5. 转: 多版本并发控制(MVCC)在分布式系统中的应用 (from coolshell)

    from:  http://coolshell.cn/articles/6790.html 问题 最近项目中遇到了一个分布式系统的并发控制问题.该问题可以抽象为:某分布式系统由一个数据中心D和若干业务 ...

  6. 多版本号并发控制(MVCC)在实际项目中的应用

    近期项目中遇到了一个分布式系统的并发控制问题.该问题能够抽象为:某分布式系统由一个数据中心D和若干业务处理中心L1,L2 - Ln组成:D本质上是一个key-value存储,它对外提供基于HTTP协议 ...

  7. Kudu的概念术语

    不多说,直接上干货! Columnar Data Store(列式数据存储) Kudu 是一个 columnar data store(列式数据存储).列式数据存储在强类型列中.由于几个原因,通过适当 ...

  8. 极客时间 mysql实战45讲下载读 08讲事务到底是隔离的还是不隔离的 笔记

    笔记体会: 1.innodb支持RC和RR隔离级别实现是用的一致性视图(consistent read view) 2.事务在启动时会拍一个快照,这个快照是基于整个库的.基于整个库的意思就是说一个事务 ...

  9. MySQL实战45讲学习笔记:第八讲

    一.今日内容概要 我在第 3 篇文章和你讲事务隔离级别的时候提到过,如果是可重复读隔离级别,事务 T 启动的时候会创建一个视图 read-view,之后事务 T 执行期间,即使有其他事务修改了数据,事 ...

随机推荐

  1. Docker使用Dockerfile构建新的镜像

    构建镜像步骤; 1.创建Dockerfile文件,该文件是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明. vim Dockerfile //每一个指令都会在镜像上创建一个新 ...

  2. (一)什么是Rabbitmq

    1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式: 同步通讯:就像打电话,需要实时响应. 异步通讯:就像发邮件,不需要马上回复. 两种方式各有优劣,打电话可以立即得到响应,但是你 ...

  3. Spring中的Environment外部化配置管理详解

    Environment的中文意思是环境,它表示整个spring应用运行时的环境信息,它包含两个关键因素 profiles properties profiles profiles这个概念相信大家都已经 ...

  4. 记一次 .NET 某供应链WEB网站 CPU 爆高事故分析

    一:背景 1. 讲故事 年前有位朋友加微信求助,说他的程序出现了偶发性CPU爆高,寻求如何解决,截图如下: 我建议朋友用 procdump 在 cpu 高的时候连抓两个dump,这样分析起来比较稳健, ...

  5. VMware vSphere,ESXi和vCenter的关系和区别

    VMware Inc.是一家软件公司.它开发了很多产品,尤其是各种云解决方案 .他的云解决方案包括云产品,数据中心产品和桌面产品等. vSphere是在数据中心产品下的一套软件.vSphere类似微软 ...

  6. Spring5基础

    基于Spring 5.2.6 版本. Spring概念 IOC容器 IOC底层原理的演进过程--本质就是为了高内聚,低耦合 在原始方式中,我们通过new创建对象来实现创建对象的逻辑,但是这样做当对象路 ...

  7. Clickhouse写入问题汇总

    Clickhouse写入问题汇总 Zookeeper相关 当clickhouse在建表时使用了Replicated引擎族时, 会对zookeeper有非常重的依赖, 这时候就要注意zookeeper集 ...

  8. 【C# .Net GC】强制垃圾回收 和System GC

    属性 GC.MaxGeneration:获取系统当前支持的最大代数. 方法 GC.GetTotalMemory(bool forceFullCollection) 方法  true表示该方法先做垃圾收 ...

  9. 【windows 访问控制】十一、C# 实操 对象 System.Security.AccessControl 命名空间

    AccessControl 命名空间 结构图 解说: DirectorySecurity=目录ACLFileSecurity=文件ACLFileSystemAuditRule=目录和文件中SACL中的 ...

  10. 原生数据类型 nint,nuint,nfloat

    原生数据类型根据操作系统32位 64位的不同,用这个关键定义的数据大小也不一样. 比如 nint 在 Xamarin.iOS 中,是 native int(原生整数)的缩写.当设备是 Apple 发布 ...