MVCC原理

article/2025/11/9 23:17:45

在并发读写数据库时,读操作可能会不一致的数据(脏读)。为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问。由于,加锁会将读写操作串行化,所以不会出现不一致的状态。但是,读操作会被写操作阻塞,大幅降低读性能。在java concurrent包中,有copyonwrite系列的类,专门用于优化读远大于写的情况。而其优化的手段就是,在进行写操作时,将数据copy一份,不会影响原有数据,然后进行修改,修改完成后原子替换掉旧的数据,而读操作只会读取原有数据。通过这种方式实现写操作不会阻塞读操作,从而优化读效率。而写操作之间是要互斥的,并且每次写操作都会有一次copy,所以只适合读大于写的情况。

MVCC的原理与copyonwrite类似,全称是Multi-Version Concurrent Control,即多版本并发控制。在MVCC协议下,每个读操作会看到一个一致性的snapshot,并且可以实现非阻塞的读。MVCC允许数据具有多个版本,这个版本可以是时间戳或者是全局递增的事务ID,在同一个时间点,不同的事务看到的数据是不同的。

实现原理: 

------------------------------------------------------------------------------------------> 时间轴

|-------R(T1)-----|

|-----------U(T2)-----------|

如上图,假设有两个并发操作R(T1)和U(T2),T1和T2是事务ID,T1小于T2,系统中包含数据a = 1(T1),R和W的操作如下:

R:read a (T1)

U:a = 2    (T2)

R(读操作)的版本T1表示要读取数据的版本,而之后写操作才会更新版本,读操作不会。在时间轴上,R晚于U,而由于U在R开始之后提交,所以对于R是不可见的。所以,R只会读取T1版本的数据,即a = 1。

由于在update操作提交之前,不能影响已有数据的一致性,所以不会改变旧的数据,update操作会被拆分成insert + delete。需要标记删除旧的数据,insert新的数据。只有update提交之后,才会影响后续的读操作。而对于读操作而且,只能读到在其之前的所有的写操作,正在执行中的写操作对其是不可见的。

上面说了一堆的虚的理论,下面来点干活,看一下mysql的innodb引擎是如何实现MVCC的。innodb会为每一行添加两个字段,分别表示该行创建的版本和删除的版本,填入的是事务的版本号,这个版本号随着事务的创建不断递增。在repeated read的隔离级别(事务的隔离级别请看这篇文章)下,具体各种数据库操作的实现:

select:满足以下两个条件innodb会返回该行数据:(1)该行的创建版本号小于等于当前版本号,用于保证在select操作之前所有的操作已经执行落地。(2)该行的删除版本号大于当前版本或者为空。删除版本号大于当前版本意味着有一个并发事务将该行删除了。

insert:将新插入的行的创建版本号设置为当前系统的版本号。

delete:将要删除的行的删除版本号设置为当前系统的版本号。

update:不执行原地update,而是转换成insert + delete。将旧行的删除版本号设置为当前版本号,并将新行insert同时设置创建版本号为当前版本号。

其中,写操作(insert、delete和update)执行时,需要将系统版本号递增。

由于旧数据并不真正的删除,所以必须对这些数据进行清理,innodb会开启一个后台线程执行清理工作,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫做purge。

通过MVCC很好的实现了事务的隔离性,可以达到repeated read级别,要实现serializable还必须加锁

其中对于MVCC的描述比较容易理解,特此贴图备忘

图1:事务T1改变数据V1,将其改为数据V2,在堆中,数据如下图

 

图2:事务T3改变了V2,将其改为V3,在堆中,数据如下图:目前事务T2还在活动中,所以V1和V2属于recently dead状态,而不是真的dead状态。

 

 

图3:从可视性而言,事务T0只能看到数据V1。因为它早于事务T1启动。

 

 

图4:事务T1提交后,事务T2启动,此时事务T3尚未启动,故T2可以看到T1提交后的数据V2。

 

 

 

图5:事务T3提交后,事务T4启动,故T4只能看到数据V3。

 

 

图6: 前面说过,当还有事务活动中访问数据V1和V2,V1和V2的状态是recently dead。

当T0和T2都结束,已经没有事务在访问数据V1和V2了,此时V1和V2为dead状态,所以V1和V2都成为VACUUM的处理对象了。

 


http://chatgpt.dhexx.cn/article/ltHkltrN.shtml

相关文章

MVCC机制

MVCC 1. MVCC是什么? MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。 MVCC的具体…

MVCC实现原理

1、什么是MVCC mvcc多版本并发控制。 mvcc在mysql innodb中主要是为了提高数据库并发性能,用更好的方式去处理读写冲突,做到即使有读写冲突时,也能做到不加索,非阻塞并发读。。 2、实现原理: mvcc的实现是通过保存…

MySQL的MVCC及实现原理

一 概要 1.什么是 MVCC ? MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。 MVCC 在 MySQL…

InnoDB MVCC 机制

本文详细的介绍了什么是MVCC?为什么要有MVCC?以及MVCC的内部实现原理:包括Undo Log的版本链是如何组织的,RR、RC两个级别下一致性读是如何实现的等。通过案例、插图,以最通俗易懂的方式,让你彻底掌握MVCC的…

mysql mvcc 实例说明_Mysql MVCC

一、MVCC概述 MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。整个MVCC多并发控制的目的就是为了实现读-写冲突不加锁,提高并发读写性能,而这个读指的就是快照度, 而非当前读,当前读实际上是一种加锁的…

MVCC

一、什么是MVCC MVCC(Multiversion concurrency control )是一种多版本并发控制机制。 二、MVCC是为了解决什么问题? 并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操…

MVCC详解

一、前言 全称Multi-Version Concurrency Control,即多版本并发控制,主要是为了提高数据库的并发性能。以下文章都是围绕InnoDB引擎来讲,因为myIsam不支持事务。 同一行数据平时发生读写请求时,会上锁阻塞住。但mvcc用更好的方式…

MVCC 机制的原理及实现

什么是 MVCC MVCC (Multiversion Concurrency Control) 中文全程叫多版本并发控制,是现代数据库(包括 MySQL、Oracle、PostgreSQL 等)引擎实现中常用的处理读写冲突的手段,目的在于提高数据库高并发场景下的吞吐性能。 如此一来…

深入浅出:MVCC详解

什么是MVCC: MVCC(Multi Version Concurrency Control的简称),代表多版本并发控制。与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。 MVCC最大的优势:读不加锁,读写不冲突。在读多写少…

什么是MVCC?MVCC解决了什么问题?MVCC的实现原理?

1.什么是MVCC? MVCC全称是【Multi-Version ConCurrency Control】,即多版本控制协议。 多版本控制(Multiversion Concurrency Control): 指的是一种提高并发的技术。最早的数据库系统,只有读读之间可以并发&#xff…

MVCC详解,深入浅出简单易懂

一、什么是MVCC? mvcc,也就是多版本并发控制,是为了在读取数据时不加锁来提高读取效率和并发性的一种手段。 数据库并发有以下几种场景: 读-读:不存在任何问题。读-写:有线程安全问题,可能出…

【MySQL笔记】正确的理解MySQL的MVCC及实现原理

MVCC多版本并发控制 如果觉得对你有帮助,能否点个赞或关个注,以示鼓励笔者呢?!博客目录 | 先点这里 !首先声明,MySQL 的测试环境是 5.7 前提概要 什么是 MVCC什么是当前读和快照读?当前读&…

Oracle自定义函数

使用Navicat的话,可以点击函数,新建函数,根据引导完成一个函数的基本搭建。 语法和Java类似,其中对于变量赋值要使用 : 进行赋值。 具体语法可以参考一下 Oracle 自定义函数语法与实例_桑汤奈伊伏的博客-CSDN博客_oracle 自定义函…

Oracle 创建函数

Oracle创建函数是通过PL/SQL自定义编写的,通过关键字function按照自己的需求把复杂的业务逻辑封装进PL/SQL函数中,函数提供一个返回值,返回给使用者。这样使用者就不需要去理解业务逻辑,把PL/SQL函数中的业务逻辑交给专门的开发人…

Oracle函数的使用

在进行select查询的时候,可以为列指定函数,函数是sql语句中的一个非常有用的特性,oracle内置了用于处理字符,数字,日期及转换的各种函数,使用函数能够执行数据计算,修改列数据的显示&#xff0c…

Oracle函数【详细 包括举例】

概述 Oracle SQL 提供了用于执行特定操作的专用函数。这些函数大大增强了 SQL 语言的功能。函数可以接受零个或者多个输入参数,并返回一个输出结果。 Oracle 数据库中主要使用两种类型的函数: 1. 单行函数:对每一个函数应用在表的记录中时&a…

Oracle 函数编写

CREATE OR REPLACE FUNCTION f_homestay_count (wkt_poly CLOB ) RETURN NUMBER IS result NUMBER ; BEGINSELECTCOUNT (*) INTO resultFROMHOMESTAY_BASIC TWHEREsdo_anyinteract (T .geom_point,sdo_geometry (wkt_poly, 4326)) TRUE; RETURN (result) ;END ;因为之前都是…

Oracle 自定义函数

语法结构 CREATE [OR REPLACE] FUNCTION 定义的函数名称(参数名1 参数类型,参数名2 参数类型, ...) RETURN 返回值类型 AS/IS 返回值形参 形参类型实例化 BEGIN 方法体 (其中用到if判断的话,每一个if对应一个end if,出现几次if就会有几个end…

oracle常用函数

1.sign sign函数是根据给的数为正数,就返回1,0返回0,负数返回-1。需要注意sign(这个括号里面只能是个字段),在括号中写个子查询直接就报错了! 2.decode 用法: decode(条件,值1,返回值1,值2,返回…

Oracle(四)Oracle 函数

目录 函数介绍Oracle字符型函数Oracle日期型函数系统日期、时间函数:数据库时区函数:给日期加上指定的月份函数:月份最后一天函数:指定日期后一周的日期函数:返回指定日期中特定部分的函数:返回两个日期间的月份数:日期…