首页 > 其他分享 >MVCC详解

MVCC详解

时间:2024-06-24 09:02:30浏览次数:3  
标签:事务 transaction 隔离 版本号 详解 MVCC mvcctest

什么是MVCC:

MVCC(Multi Version Concurrency Control的简称),代表多版本并发控制。与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。

MVCC最大的优势:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能学习MVCC前,我们先了解下Mysql架构和数据库事务隔离级别

MySQL 架构:

MySQL的架构不同于其他数据库,它的插件式的存储引擎架构可以在多种不同场景中应用并发挥良好作用。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

各层介绍:

1、连接层
最上层是客户端,包含本地sock通信和大多数基于客户端/服务端工具实现的类似于tcp/ip的通信。

2、服务层


3、引擎层

存储引擎负责MySQL中数据的存储和提取,服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。

show engines:查看所有的数据库引擎

 

show variables like ‘%engine%’ 查看默认的数据库引擎

MyISAM和InnoDB对比

 

4、存储层
数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。

四种数据库事务隔离级别:

为了解决并发事务存在的脏读、不可重复读、幻读等问题,数据库设计了四种隔离级别。分别是读未提交,读已提交,可重复读,串行化(Serializable)。

1、读未提交

读未提交隔离级别,只限制了两个数据不能同时修改,但是修改数据的时候,即使事务未提交,都是可以被别的事务读取到的,这级别的事务隔离有脏读、重复读、幻读的问题;

2、读已提交

读已提交隔离级别,当前事务只能读取到其他事务提交的数据,所以这种事务的隔离级别解决了脏读问题,但还是会存在重复读、幻读问题;

3、可重复读

可重复读隔离级别,限制了读取数据的时候,不可以进行修改,所以解决了重复读的问题,但是读取范围数据的时候,是可以插入数据,所以还会存在幻读问题;

4、串行化

事务最高的隔离级别,在该级别下,所有事务都是进行串行化顺序执行的。可以避免脏读、不可重复读与幻读所有并发问题。但是这种事务隔离级别下,事务执行很耗性能。

四种隔离级别具体特性

 

5、数据库是如何保证事务的隔离性的呢?

数据库是通过加锁,来实现事务的隔离性的。这就好像,如果你想一个人静静,不被别人打扰,你就可以在房门上加上一把锁。

加锁确实好使,可以保证隔离性。比如串行化隔离级别就是加锁实现的。但是频繁的加锁,导致读数据时,没办法修改,修改数据时,没办法读取,大大降低了数据库性能。

那么,如何解决加锁后的性能问题的?

答案就是,MVCC多版本并发控制!它实现读取数据不用加锁,可以让读取数据同时修改。修改数据时同时可读取。

MVCC实现:

MVCC是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号(system version number)。

每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

下面看一下在REPEATABLE READ隔离级别下,MVCC具体是如何操作的。

  • SELECTInnoDB会根据以下两个条件检查每行记录:
    1. InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
    2. 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。
  • INSERTInnoDB为新插入的每一行保存当前系统版本号作为行版本号。
  • DELETEInnoDB为删除的每一行保存当前系统版本号作为行删除标识。
  • UPDATEInnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
    保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作

举例说明:

create table mvcctest( 
id int primary key auto_increment, 
name varchar(20));
create table mvcctest( 
id int primary key auto_increment, 
name varchar(20));

transaction 1:

start transaction;
insert into mvcctest values(NULL,'mi');
insert into mvcctest values(NULL,'kong');
commit;
start transaction;
insert into mvcctest values(NULL,'mi');
insert into mvcctest values(NULL,'kong');
commit;

假设系统初始事务ID为1;

 

transaction 2:

start transaction;
select * from mvcctest;  //(1)
select * from mvcctest;  //(2)
commit
start transaction;
select * from mvcctest;  //(1)
select * from mvcctest;  //(2)
commit

SELECT:

假设当执行事务2的过程中,准备执行语句(2)时,开始执行事务3:

transaction 3:

start transaction;
insert into mvcctest values(NULL,'qu');
commit;
start transaction;
insert into mvcctest values(NULL,'qu');
commit;

 

事务3执行完毕,开始执行事务2 语句2,由于事务2只能查询创建时间小于等于2的,所以事务3新增的记录在事务2中是查不出来的,这就通过乐观锁的方式避免了幻读的产生。

UPDATE:

假设当执行事务2的过程中,准备执行语句(2)时,开始执行事务4:

transaction session 4:

start transaction;
update mvcctest set name = 'fan' where id = 2;
commit;
start transaction;
update mvcctest set name = 'fan' where id = 2;
commit;

InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的行的删除时间。

 

事务4执行完毕,开始执行事务2 语句2,由于事务2只能查询创建时间小于等于2的,所以事务修改的记录在事务2中是查不出来的,这样就保证了事务在两次读取时读取到的数据的状态是一致的。

DELETE:

假设当执行事务2的过程中,准备执行语句(2)时,开始执行事务5:

transaction session 5:

start transaction;delete from mvcctest where id = 2;commit;

事务5执行完毕,开始执行事务2 语句2,由于事务2只能查询创建时间小于等于2、并且过期时间大于等于2,所以id=2的记录在事务2 语句2中,也是可以查出来的,这样就保证了事务在两次读取时读取到的数据的状态是一致的。

标签:事务,transaction,隔离,版本号,详解,MVCC,mvcctest
From: https://www.cnblogs.com/gdjgs/p/18264291

相关文章

  • C语言编译和链接详解(通俗易懂,深入本质)
    我们平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(ExecutableProgram)。在Windows下,可执行程序的后缀有.exe和.com(其中.exe比较常见);在类UNIX系统(Linux、MacOS等)下,可执行程序没有特定的后缀,系统根据文件的头部信息来判断是否是可执行程序。可......
  • k8s手撕架构图+详解
    1.架构图这个架构图展示了一个典型的Kubernetes集群的结构和各个组件的作用。以下是详细解释2.架构图整体介绍 ControllerPlane(控制平面)负责管理和控制整个Kubernetes集群。包含以下组件:etcd:一个分布式键值存储,存储集群的所有数据。Scheduler(调度器):负责将Pod......
  • Kubernetes之Service详解
    本文尝试从Service暴露服务方式、Service控制器实现原理、使用规范等方面对Kubernetes中的Service进行详细介绍。一、Kubernetes中的pod有哪些暴露服务的方式各种Kubernetes中暴露服务的方式都有其独特的优缺点,根据具体的使用场景和需求,选择合适的方式非常重要。下面......
  • 【Linux详解】冯诺依曼架构 | 操作系统设计 | 斯坦福经典项目Pintos
    目录一.冯诺依曼体系结构(VonNeumannArchitecture)注意事项存储器的意义:缓冲数据流动示例二.操作系统(OperatingSystem)操作系统的概念操作系统的定位与目的操作系统的管理系统调用和库函数操作系统的管理:sum三.系统调用实现示例:Pintos项目Step1:进入ex......
  • Structured Steaming结构化流详解:大案例解析(第12天)
    系列文章目录一、结构化流介绍(了解)二、结构化流的编程模型(掌握)三、Spark和Kafka整合,流处理,批处理演示(掌握)四、物联网数据分析案例(熟悉)文章目录系列文章目录前言StructuredSteaming一、结构化流介绍(了解)1、有界和无界数据2、基本介绍3、使用三大步骤(掌握)4、回......
  • Postman接口测试工具详解
    个人名片......
  • 【操作系统】信号Signal超详解|捕捉函数
    ......
  • Postman接口测试工具详解
    一、引言在现代软件开发和测试流程中,接口测试占据了举足轻重的地位。接口作为系统与系统之间、模块与模块之间数据交互的桥梁,其稳定性和可靠性直接关系到整个系统的性能和用户体验。Postman作为一款强大的接口测试工具,凭借其简单易用、功能丰富等特点,深受开发者和测试人员......
  • C语言中操作符详解(二)
    OK,今天继续为诸君带来有关C语言中操作符的讲解一.位操作符 C语言中的位操作符我相信大家并不陌生,我们在之前就已经接触过了一些位操作符(位操作符的操作数只能是整数):(1)&:按位与(同为1才为1,否则为0)(2)| :按位或(有1就为1)(3)^:按位异或(不同为1,否则为0)(4)~:按位......
  • 深度解析RocketMq源码-高可用存储组件(一) raft协议详解
    1.绪论前面的文章已经分析过,以前rocketmq通过主从复制的思想实现系统的高可用,即在搭建集群的时候会手动的设置一个主节点和从节点,在写入数据的时候,会先写入到主broker,然后再同步到从节点中。但是这样会有一个问题,就是主节点宕机过后,需要手动的修改从节点成为新的主节点。在roc......