mysql的mvcc详解

一 MVCC的作用

1.1 mvcc的作用

1.MVCC(Multiversion Concurrency Control)多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制,使得在InnoDB事务隔离级别下执行一致性读操作有了保障。

2.mysql中的InnoDB中实现了MVCC主要是为了提高数据库的并发性能,在无锁的情况下也能处理读写并发,大大提高数据库的并发度。

3..MySQl中只有InnoDB支持MVCC,其他存储引擎不支持

4.为了查询一些正在被其他事务更新的值的时候,能够查到它们被更新之前的值,这样做就能在查询的时候不必等待更新事务的提交。

在InnoDB中,会对增删改操作自动添加排它锁,因此两个事务不会出现脏写的情况,也就是不会出现两个事务交叉着对同一条记录进行修改,必须等待第一个事务提交才能进行第二个事务。

1.2 快照读与当前读的区别与联系

1.MVCC在InnoDB中的实现主要是为了提高数据库的并发性能,用更好的方式处理读写冲突,做到即使有读写冲突,也能不加锁实现非堵塞并发读,这个读指的是快照读而不是当前读。

2.当前读实质上是一种加锁的操作,是悲观锁的体现;而MVCC是采用乐观锁的一种方式

1.3 快照读

1.快照读,顾名思义读取的是一份快照数据,所以读到的并不一定是最新数据,可能是历史数据。

2.简单的select查询就是快照读,不加锁非阻塞读,降低数据库的开销。

3.但是快照读在隔离级别是串行化级别是没有意义的,因为串行化的sql都是排队执行的,不存在并发,所以就会变成当前读。

1.4 当前读

当前读获取的数据是最新数据,而且在读取时不能被其他修改的,所以会对读取的记录加锁来控制。

加锁的SELECT(共享或排它锁)或者对数据进行增删改操作(自动添加排它锁)都会进行当前读。

select * from ajisun where id > 1 lock in share mode;// 或者select * from ajisun where id >1 for update;

1.5 mvcc可以解决问题

  1. 读写之间的堵塞问题,提高事务的并发读写能力

  2. 降低了死锁的概率,MVCC采用了乐观锁的方式,读取数据的时候不需要加锁,对于写操作,也只要锁定必要的行

  3. 解决快照读问题,当查询数据库某个时间节点的快照的时候,只能查看到在这个节点之前提交的事务的结果而看不到时间点之后事务提交的更新结果

1.6 mvcc面试题:mvcc是怎么实现的

mvcc 是多版本并发控制,通过生成记录的历史版本解决幻读问题,并提高数据库的性能,无锁实现读写并发操作。

1.mvcc 的实现主要是通过三个隐藏字段,undo log以及readView 实现的。

2.三个隐藏字段分别是隐藏主键,事务ID,回滚指针。

3.undo log是各个事务修改同一条记录的时候生成的历史记录,方便回滚,同时会生成一条版本链。

4.readView是事务在进行快照读的时候生成的记录快照,用于判断数据的可见性。

5.描述readView 可见性判断规则。

二  MVCC实现原理

2.1 原理

​ MVCC的实现依赖于:隐藏字段Undo logRead View 

2.2 undo log

2.2.1 undo Log的作用

所谓的版本链就是在MVCC中,多个事务对同一行记录进行更新会产生多个历史快照,这些记录保存在Undo Log里,这些undo日志通过回滚指针串联在一起。

undo log就是回滚日志,在insert/update/delete变更操作的时候生成的记录方便回滚。

当进行insert操作的时候,产生的undo log只有在事务回滚的时候需要,如果不回滚在事务提交之后就会被删除。

当进行update和delete的时候,产生的undo log不仅仅在事务回滚的时候需要,在快照读的时候也是需要的,所以不会立即删除,只有等不再用到这个日志的时候才会被mysql purge线程统一处理掉(delete操作也只是打一个删除标记,并不是真正的删除)。

2.2.2 undo Log的组成

​ undo log的版本链,对于使用InnoDB存储引擎的表来说,它的聚簇记录中包含两个必要的索引列:

1.trx_id:每次事务对聚簇记录进行修改的时候,就会将该事务的id复制给trx_id隐藏列

2.roll_pointer:每次对每条聚簇索引进行改动的时候,都会将旧的版本信息写入undo log中,通过回滚指针就能找到记录修改前的信息。

2.2.3 undo Log的案例

1.假设两个事务id分别为10、20的事务分别对这条记录进行Update操作。

2.每次对记录进行改动,都会记录一条undo log,每个undo log都包含创建它的事务id,每条undo log都会有一个roll pointerINSERT操作不会有,因为插入没有更新的版本),这些undo log通过roll pointer连接起来,串成一个链表,这个链表就成为undo log 版本链。

3.如下图:

2.3 隐藏字段

除了我们正常业务涉及的字段外,InnoDB在内部向数据库表中添加三个隐藏字段:

1.DB_TRX_ID:6-byte的事务ID。插入或更新行的最后一个事务的事务ID

2.DB_ROLL_PTR:7-byte的回滚指针。就是指向对应某行记录的上一个版本,在undo log中使用。

3.DB_ROW_ID:6-byte的隐藏主键。如果数据表中没有主键,那么InnoDB会自动生成单调递增的隐藏主键(表中有主键或者非NULL的UNIQUE键时都不会包含 DB_ROW_ID列)。

如上面的表没有设计primary key,其中id/name/city是我们的业务字段,那么加上隐藏字段应该如下

 

2.4  ReadView

2.4.1 ReadView的作用

ReadView 是事务快照读的时候产生的数据读视图,在该事务执行快照读的那一刻,会生成一个数据系统当前的快照,记录并维护系统当前活跃事务的id,事务的id值是递增的。

Read View就是事务在使用MVCC机制在进行快照读操作时产生的快照,ReadView 的最大作用就是判断数据的可见性,当某个事务执行快照读的时候,会对此记录创建一个ReadView 的视图,在整个事务期间根据某些条件判断该事务能够看到的版本链上的哪条历史数据。

2.4.2  ReadView的组成

  1. creator_id:创建这个Read View的事务id

  2. trx_ids:表示创建这个Read View的时候正在活跃的事务id列表

  3. up_limit_id:活跃的事务中最小的id

  4. low_limit_id:表示生成low_limit_id时系统应该分配给下一个事务的id值,low_limit_id是系统最大的事务id(而不是活跃的最大事务id)

***low_limit_id并不是trx_ids的最大值而是系统能够分配的事务id最大值,事务id是递增分配的,并且只有事务在进行增删改操作的时候才会分配事务ID。比如现在有1 2 5三个事务,那么id为5的事务提交后,一个新事务在生成ReadView的时候,trx_ids就包括1 2,up_limit_id就是1,low_limit_id就是6

此时如果有事务创建Read View,则

  • trx_ids=[trx2, trx3, trx5, trx8]
  • up_limit_id=trx2
  • low_limit_id=trx8+1

2.4.3  ReadView的判断流程

当查询一条数据的时候,系统

  1. 首先获取查询操作的事务的版本号
  2. 获取当前系统的ReadView
  3. 将查询到的数据与ReadView中的事务版本号进行比较
  4. 如果不符合ReadView的规则,则通过回滚指针形成的Undo Log版本链undo log中获取符合规则的历史快照
  5. 返回符合规则的数据

快照记录创建这个Read View的事务id、活跃的事务中最小的id、系统最大的事务id,并且InnoDB会为每个事务构建了一个数组,用来记录并维护系统当前活跃事务的ID(活跃指的是启动了还没有提交),等到访问某条记录的时候,就可以根据上面记录的内容判断记录版本对当前事务可不可见

1.如果Read Viewcreator_id当前事务的id相同,则意味着当前事务在访问它修改过的id,所以该记录版本可以被事务访问

2.如果当前访问版本记录的trx_id小于Read Viewup_limit_id,则意味着修改该数据版本的事务已经提交,所以该版本的记录可以被当前事务访问

3.如果当前访问版本记录的trx_id大于等于Read Viewlow_limit_id,则意味着创建该数据版本的事务是在ReadView生成之后才出现的,因此当前事务不能访问

4.如果当前访问版本记录的trx_idRead Viewup_limit_idlow_limit_id之间,则需要判断trx_id是否在Read Viewtrx_ids活跃事务列表中,如果在则说明事务还没有提交当前事务不能访问,否则可以访问

5.如果某个版本对当前事务不可见,那么顺着版本链找到下个版本记录,然后继续上面的对比规则,直到找到版本链中的最后一个版本,如果最后一个版本都不可见,那么该条记录对此事务完全不可见,也就查不到这个记录。

2.5 不同隔离级别使用Readview

1.读未提交:能够读取未提交的事务修改的数据,所以直接读取最新的记录就可以,不必使用MVCC

2.读已提交:不能读取未提交的事务修改的数据,并且不能进行重复读取,事务中,每次快照读都会新生成一个快照和ReadView,这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因。

3.可重复读:不能读取未提交的事务修改的数据,并且能进行重复读取,所以只在第一次查询的时候获取一次ReadView,之后查询都只查看已经生成的ReadView副本

4.可串行化:InnoDB规定使用加锁的方式来访问记录,通过加锁的方式让所有sql都串行化执行了,也是读最新的,不存在快照读ReadView。

https://www.cnblogs.com/tod4/p/17384677.html

MySQL进阶系列:多版本并发控制mvcc的实现

2.6  mvcc解决幻读问题

MySQL在Repeatable Read隔离级别下是可以解决幻读问题的,解决的方案有两种:

1.使用MVCC进行快照读,写使用临键锁。添加的临键锁不会影响快照读,只会影响到想要获取锁的读操作

2.读写加锁,也就是使用可串行化的隔离模式。

2.6.1 mvcc解决幻读

读操作利用多版本并发控制MVCC),写操作加锁。

MVCC就是生成一个ReadView,通过ReadView能够找到符合条件的记录版本(历史版本由undo log提供查询),查询语句执行查询已经提交的事务做出的更改,对于没由提交的事务和ReadView创建之后的事务做出的更改是看不到的。而写操作肯定是针对的最新版本的记录,因此读记录的历史版本和写操作的最新记录版本并不会冲突,也就是采用MVCC时,读写操作并不会冲突。

普通的SELECT语句在READ COMMITTED 和 REPEATABLE READ隔离级别下的读操作就是利用MVCC进行的读

1.READ COMMITTED:由于不会读取没有提交的事务修改的数据版本,因此避免了脏读问题

2.REPEATABLE READ:由于不会读取Read View创建之后的事务更改的数据(一个事务只有在第一次执行SELECT语句才会生成一个Read View,之后的SELECT语句都在复用),因此避免了可重复读和幻读问题。

2.6.2 通过加锁的方式

读、写操作都采用加锁的方式

在一些业务场景中,不允许读取数据的历史版本,即每次都需要去读取磁盘中最新的数据,这样也就意味着读操作也需要和写操作一样排队执行。

如此一来,脏读不可重复读问题都得到了解决,因为读操作和写操作的串行执行,不会出现一个事务读取另一个未提交事务的数据以及一个事务读取过程中另一个事务修改数据提交导致前一个事务前后读取数据不一致的情况(第二个事务根本无法开始)

****但是,幻读问题有些尴尬,试想一个事务在进行读操作,因此给表中的一定范围内的数据加锁,但是另一个事务要写的这个幻影数据可不在这个范围里面,也就是两个读写操作并不会冲突,仍然会出现幻读问题解决这一个问题的办法就是写操作使用临键锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/149768.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go Gin Gorm Casbin权限管理实现 - 3. 实现Gin鉴权中间件

文章目录 0. 背景1. 准备工作2. gin中间件2.1 中间件代码2.2 中间件使用2.3 测试中间件使用结果 3. 添加权限管理API3.1 获取所有用户3.2 获取所有角色组3.3 获取所有角色组的策略3.4 修改角色组策略3.5 删除角色组策略3.6 添加用户到组3.7 从组中删除用户3.8 测试API 4. 最终目…

Leetcode1071. 字符串的最大公因子(三种方法,带详细解析)

🎶Leetcode1071. 字符串的最大公因子 对于字符串 s 和 t,只有在 s t … t(t 自身连接 1 次或多次)时,我们才认定 “t 能除尽 s”。 给定两个字符串 str1 和 str2 。返回 最长字符串 x,要求满足 x 能除尽…

c#设计模式-行为型模式 之 状态模式

🚀简介 状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变其行为,我们可以通过创建一个状态接口和一些实现了该接口的状态类来实现状态模式。然后,我们可以创建一个上下文类,它会根据其当前的状态对象来改…

学习笔记|ADC反推电源电压|扫描按键(长按循环触发)|课设级实战练习|STC32G单片机视频开发教程(冲哥)|第十八集:ADC实战

文章目录 1.ADC反推电源电压测出Vref引脚电压的意义?手册示例代码分析复写手册代码Tips:乘除法与移位关系为什么4096后面还有L 2.ADC扫描按键(长按循环触发)长按触发的实现 3.实战小练1.初始状态显示 00 - 00 - 00,分别作为时,分&#xff0c…

黑豹程序员-架构师学习路线图-百科:JSON替代XML

文章目录 1、数据交换之王2、XML的起源3、JSON诞生4、什么是JSON 1、数据交换之王 最早多个软件之间使用txt进行信息交互,缺点:纯文本,无法了解其结构;之后使用信令,如:电话的信令(拨号、接听、…

【程序员必看】计算机网络,快速了解网络层次、常用协议和物理设备!

文章目录 0 引言1 基础知识的定义1.1 计算机网络层次1.2 网络供应商 ISP1.3 猫、路由器、交换机1.4 IP协议1.5 TCP、UDP协议1.6 HTTP、HTTPS、FTP协议1.7 Web、Web浏览器、Web服务器1.8 以太网和WLAN1.9 Socket (网络套接字) 2 总结 0 引言 在学习的过程…

常用Redis界面化软件

对于Redis的操作,前期有过介绍【Centos 下安装 Redis 及命令行操作】。而在Redis的日常开发调试中,可使用可视化软件方便进行操作。 本篇主要介绍Redis可视化的两款工具:Redis Desktop Manager和AnotherRedisDesktopManager。 1、Redis Desk…

Aasee Api开放平台上线啦!

使用方法 首先介绍使用方法&#xff0c;只需导入一个SDK即可使用实现调用第三方的接口&#xff0c;那如何导入SDK呢&#xff0c;目前jar已经上传至maven中心仓库可直接引入到pom文件中使用&#xff0c;下面是例子&#xff1a; <dependency><groupId>io.github.Aa…

【Java 进阶篇】使用 JDBCTemplate 执行 DML 语句详解

JDBCTemplate 是 Spring 框架中的一个核心模块&#xff0c;用于简化 JDBC 编程&#xff0c;使数据库操作更加便捷和高效。在本文中&#xff0c;我们将重点介绍如何使用 JDBCTemplate 执行 DML&#xff08;Data Manipulation Language&#xff09;语句&#xff0c;包括插入、更新…

SNP Glue:SAP数据导入到其他系统的多种方式

SAP是一款功能强大的企业资源计划&#xff08;ERP&#xff09;软件&#xff0c;许多企业依赖SAP来管理和处理其核心业务数据。然而&#xff0c;有时候企业需要将SAP中的数据导入到其他系统中&#xff0c;以实现更广泛的数据共享和集成&#xff0c;便于企业实现数据智能。本文将…

计算摄像技术02 - 颜色空间

一些计算摄像技术知识内容的整理&#xff1a;颜色视觉与感知特性、颜色空间和基于彩色滤镜阵列的彩色感知。 文章目录 一、颜色视觉与感知特性 &#xff08;1&#xff09;色调 &#xff08;2&#xff09;饱和度 &#xff08;3&#xff09;明度 二、颜色空间 &#xff08;1&…

[架构之路-228]:目标系统 - 纵向分层 - 计算机硬件与体系结构 - 硬盘存储结构原理:如何表征0和1,即如何存储0和1,如何读数据,如何写数据(修改数据)

目录 前言&#xff1a; 一、磁盘的盘面组成 1.1 磁盘是什么 ​编辑1.2 磁盘存储介质 1.3 磁盘数据的组织 1.3.1 分层组织&#xff1a;盘面号 1.3.2 扇区和磁道 1.3.3 数据 1.3.4 磁盘数据0和1的存储方式 1.3.5 磁盘数据0和1的修正方法 1.3.6 磁盘数据0和1的读 二、…

基于腾讯云的OTA远程升级

一、OTA OTA即over the air,是一种远程固件升级技术&#xff0c;它允许在设备已经部署在现场运行时通过网络远程更新其固件或软件。OTA技术有许多优点&#xff0c;比如我们手机系统有个地方做了优化&#xff0c;使用OTA技术我们就不用召回每部手机&#xff0c;直接通过云端就可…

(一)正点原子STM32MP135移植——准备

一、简述 使用板卡&#xff1a;正点原子的ATK-DLMP135 V1.2 从i.mx6ull学习完过来&#xff0c;想继续学习一下移植uboot和内核的&#xff0c;但是原子官方没有MP135的移植教程&#xff0c;STM32MP157的移植教程用的又是老版本的代码&#xff0c;ST官方更新后的代码不兼容老版本…

Linux中的wc命令

2023年10月6月&#xff0c;周五晚上 目录 wc命令的主要功能和用法如下:统计文件行数、字数和字节数只统计行数只统计字数只统计字节数 wc命令在Linux/Unix系统中是word count的缩写,它用来统计文件的行数、字数和字节数。 wc命令的主要功能和用法如下: 统计文件行数、字数和字…

mac清理垃圾的软件有哪些?这三款我最推荐

没错&#xff0c;Mac电脑真的好用&#xff0c;但是清理系统垃圾可不是件容易的事。由于Mac系统的封闭性&#xff0c;系统的缓存垃圾常常隐藏得让人发现不了。不过&#xff0c;别担心&#xff01;有一些专业的Mac清理软件可以帮你解决这一系列问题&#xff0c;让清理垃圾变得轻松…

踩大坑ssh免密登录详细讲解

目 录 问题背景 环境说明 免密登录流程说明 1.首先要在对应的用户主机名的情况下生成密钥对&#xff0c;在A服务器执行 2.将A服务器d公钥拷贝到B服务器对应的位置 3.在A服务器访问B服务器 免密登录流程 0.用户说明 1.目前现状演示 2.删除B服务器.ssh 文件夹下面的…

【将文本编码为图像灰度级别】以 ASCII 编码并与灰度级别位混合将文本字符串隐藏到图像像素的最低位中,使其不明显研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

我在 NPM 发布了新包: con-colors

链接地址&#xff1a;npmjs.com con-colors 安装依赖 yarn add con-colors使用 导入&#xff1a; import { print } from "con-colors";使用&#xff1a; print.succ("成功的消息"); print.err("失败的消息")例子&#xff1a; import { p…

OpenResty编译安装详解

文章目录 一、概述1、OpenResty是什么2、官方文档 二、cengos安装OpenResty1、从官网下载2、目录结构3、编译安装 一、概述 1、OpenResty是什么 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台&#xff0c;其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖…