MySQL事务MVCC详解

一、概述

MVCC (MultiVersion Concurrency Control) 叫做多版本并发控制机制。主要是通过数据多版本来实现读-写分离,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读,从而提高数据库并发性能。

MVCC只在已提交读(Read Committed)和可重复读(Repeatable Read)两个隔离级别下工作,其他两个隔离级别和MVCC是不兼容的。因为未提交读,总数读取最新的数据行,而不是读取符合当前事务版本的数据行。而串行化(Serializable)则会对读的所有数据多加锁。

主要思想是:InnoDB通过undo log保存每条数据的多个版本,并且能够找回数据历史版本提供给用户读,每个事务读到的数据版本可能是不一样的。在同一个事务中,用户只能看到该事务创建快照之前已经提交的修改和该事务本身做的修改。

二、当前读和快照读

  • 快照读:读取的是历史数据,不加锁的简单 Select 都属于快照读。
select * from user where id = 1;
  • 当前读:读取的是最新数据,而不是历史的数据,加锁的 SELECT,或者对数据进行增删改都会进行当前读。
SELECT * FROM user LOCK IN SHARE MODE;
SELECT * FROM user FOR UPDATE;
INSERT INTO user values ...
DELETE FROM user WHERE ...
UPDATE user SET ...

三、MVCC 与快照读的关系

MVCC 多版本并发控制是维持一个数据的多个版本,使得读写操作没有冲突,而这只是一个抽象概念。而快照读就是 MySQL 实现 MVCC 理想模型的其中一个非阻塞读功能,快照读所读取的就是MVCC维持的多版本数据中去某个版本数据。

四、MVCC 优点

  1. 提供多版本数据,在并发读写数据库时,读写操作互不影响,提高了数据库并发读写的性能。
  2. 可以解决脏读,幻读,不可重复读等事务隔离问题。

五、MVCC 实现原理

主要是依赖每一行记录中2个隐藏字段、undo log版本链 以及 ReadView。

1. 行记录的隐藏字段
  1. trx_id:操作这个数据的事务 ID,也就是最后一个对数据插入或者更新的事务 ID 。
  2. roll_ptr:回滚指针,指向这个记录的 Undo Log 信息。
  3. row_id:隐藏的行 ID ,用来生成默认的聚集索引。如果创建数据表时没指定聚集索引,这时 InnoDB 就会用这个隐藏 ID 来创建聚集索引。
2. undo log版本链

多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(roll_pointer),连成一个链表,这个链表就称为版本链。(其实undo log 版本链的节点在事务提交之后可能是会 purge 线程清除掉的)

(1)首先开启第一个事务,事务id为1,通过insert语句往表中插入一条新记录如下:
在这里插入图片描述
由于是新插入的记录,因此它的roll_pointer指向的undo log为空。

(2)接着开启第二个事务,事务id为2,更新该行记录的name为Tom。
在这里插入图片描述

  • 在第二个事务修改该行记录时,数据库会先对该行加排他锁;
  • 然后把该行数据拷贝到 undo log 中,作为旧版本记录;
  • 拷贝完毕后,再修改该行name为Tom,并且修改隐藏字段trx_id为当前事务的id, 回滚指针roll_pointer指向拷贝到 undo log 的副本记录,既表示我的上一个版本就是它。
  • 事务提交后,释放锁。

(3)再开启第三个事务,事务id为3,修改改行记录的age为25。
在这里插入图片描述

  • 在第三个事务修改该行记录时,数据库会先对该行加排他锁;
  • 然后把该行数据拷贝到 undo log 中,作为旧版本记录;
  • 拷贝完毕后,再修改该行age为25,并且修改隐藏字段trx_id为当前事务的id, 回滚指针roll_pointer指向拷贝到 undo log 的副本记录,既表示我的上一个版本就是它。
  • 事务提交后,释放锁。
3.ReadView

Read View 就是事务进行 “快照读” 操作时候生产的 “读视图”,在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID。主要是用来做可见性判断的,即当我们某个事务执行快照读的时候,当前事务能够看到undo log版本链上的哪个版本数据。

(1)ReadView中主要属性

  1. trx_ids:当前系统中那些活跃(未提交)的读写事务ID,它数据结构为一个List。(trx_ids中的活跃事务不包括:当前事务自己)。
  2. min_trx_id:trx_ids中最小的事务id。
  3. max_trx_id:预分配事务编号,MySQL即将为下一个事务分配的事务id。
  4. creator_trx_id: 表示生成该 ReadView 的事务的 事务id。

(2)ReadView可见性判断规则

  1. 判断 trx_id = creator_trx_id,如果条件成立,则说明当前事务与进行select快照读的事务是同一个事务,那么该select是可以读取到该trx_id对应的版本;如果条件不成立,继续往下判断其他条件。
  2. 判断 trx_id < min_trx_id,如果条件成立,则说明当前事务是在进行select快照读的事务之前就已经提交了,那么该select是可以读取到该trx_id对应的版本;如果条件不成立,继续往下判断其他条件。
  3. 判断 trx_id > max_trx_id,如果条件成立,则说明当前事务是在进行select快照读的事务之后才创建的,那么该select是肯定读取不到该trx_id对应的版本;如果条件不成立,则继续往下判断其他条件。
  4. 判断 min_trx_id < trx_id < max_trx_id,如果条件成立,则说明当前事务可能在活跃的事务中,需要再判断下trx_id是否在trx_ids中,如果不在,则说明当前事务已经提交过了,那么该select就可以读取到该trx_id对应的版本;否则说明当前事务还未提交,该select也就无法读取到该trx_id对应的版本。

(3)已提交读(RC)与可重复读(RR)级别下的快照读
RC 隔离级与RR隔离级生成Read View 的时机是不同的,因为也造成了两者快照读的结果的不同。在 RC 隔离级别下,是每个快照读都会生成并获取最新的 Read View;而在 RR 隔离级别下,则是同一个事务中的第一个快照读才会创建 Read View, 之后的快照读获取的都是同一个 Read View。

undo log版本链:
在这里插入图片描述
ReadView创建实时机:
在这里插入图片描述

解析:
(1)RC级别下:
在事务D中的第一个select语句执行时,生成的ReadView中,当前系统中那些活跃(未提交)的读写事务有{3,4},创建ReadView的事务id为5,活跃事务中最新事务id为3,预分配的事务id为6。再根据undo log版本链依次与ReadView的可见性判断规则进行对比,判断哪个版本是可见的。例如:

  • 先对版本链最新的一个版本trx_id = 4进行判断:
    1.先判断 trx_id = creator_trx_id:creator_trx_id = 5,trx_id = 4,条件不成立,暂时无法证明该版本相对于当前select可见,则继续根据其他规则进行判断。
    2.继续判断 trx_id < min_trx_id:min_trx_id = 3,trx_id = 4,条件不成立,也暂时无法证明该版本相对于当前select可见,则继续根据其他规则进行判断。
    3.继续判断 trx_id > max_trx_id:max_trx_id = 6,trx_id = 4,条件不成立,也暂时无法证明该版本相对于当前select可见,则需要继续据其他规则进行判断。(如果该条件成立,则可以证明该版本相对于当前select肯定是不可见的)
    4.继续判断 min_trx_id < trx_id < max_trx_id:条件成立,说明当前事务可能在活跃的事务中,需要再判断下trx_id是否在trx_ids中,trx_id = 4在活跃的事务中,也就是当前事务还未提交,那么该select也就无法读取到该版本的数据。
    所有可见性规则判断完毕,最终得出版本链中最新的一个事务C这个版本在事务D中的第一个select语句是不可见的。
  • 再对版本链中trx_id = 3 按照上述的可见性规则依次判断:最终得出该版本在事务D中的第一个select语句也是不可见的。
  • 再对版本链中trx_id = 2 按照上述的可见性规则依次判断:最终得出该版本在事务D中的第一个select语句也是可见的。

在事务D中的第二个select语句执行时,会重新生成一个新的ReadView,此时系统中那些活跃(未提交)的读写事务有{4},创建ReadView的事务id为5,活跃事务中最新事务id为4,预分配的事务id为6。再根据undo log版本链依次与ReadView的可见性判断规则进行对比,可以得出最终该select语句的可见版本为 trx_id = 3 和 trx_id = 2,与第一个select语句查询的可见版本不一样。这也是为什RC隔离级别下,同一事务中多次使用快照读查询时会产生查询结果不一致的问题。

(2)RR级别下:
在事务D中的第一个select语句执行时,生成一个ReadView与RC级别是一样的,所以最终得到的可见版本也是只有 trx_id = 2。但是在事务D中的第二个select语句执行时,RR级别不会再生成新的ReadView,而是直接复用第一次生的的那个ReadView,所以最终判断下来,第二个select语句的可见版本也只有 trx_id = 2。这也就是为什么RR级别下同一事务中多次使用快照读查询时结果都是相同的原因。如何在事务中使用了当前读,则后面的快照读不会再复用之前的ReadView,而是重新生成一个新的ReadView,这也RR级别下无法解决幻读的原因。

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

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

相关文章

行业追踪,2023-10-18

自动复盘 2023-10-18 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

Docker是一个流行的容器化平台,用于构建、部署和运行应用程序。

文章目录 Web应用程序数据库服务器微服务应用开发环境持续集成和持续部署 (CI/CD)应用程序依赖项云原生应用程序研究和教育 &#x1f388;个人主页&#xff1a;程序员 小侯 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏&#xff1a;…

mysql查看连接池的命令

查看实时连接的个数 &#xff08;瞬时值&#xff09; SHOW STATUS LIKE Threads_connected; 查看具体的链接信息 show full processlist; 数据库链接池常见的报错 Cannot create PoolableConnectionFactory (Data source rejected establishment of connection, message fr…

Android Fragment 基本概念和基本使用

Android Fragment 基本概念和基本使用 一、基本概念 Fragment&#xff0c;简称碎片&#xff0c;是Android 3.0&#xff08;API 11&#xff09;提出的&#xff0c;为了兼容低版本&#xff0c;support-v4库中也开发了一套Fragment API&#xff0c;最低兼容Android 1.6。 过去s…

Swift使用Embassy库进行数据采集:热点新闻自动生成器

概述 爬虫程序是一种可以自动从网页上抓取数据的软件。爬虫程序可以用于各种目的&#xff0c;例如搜索引擎、数据分析、内容聚合等。本文将介绍如何使用Swift语言和Embassy库编写一个简单的爬虫程序&#xff0c;该程序可以从新闻网站上采集热点信息&#xff0c;并生成一个简单…

Redis的五大基础数据类型

String 字符串类型&#xff0c;通过set关键字和get关键字来设置字符串键值对和获取字符串键值对。 hash 哈希类型&#xff0c;结构和Map<String,Map<String,stirng>>类似。 使用hset来设置哈希&#xff0c;使用hget来获取哈希&#xff0c;hget要精确到第二个key…

苍穹外卖(八) 使用WebSocket协议完成来单提醒及客户催单功能

WebSocket介绍 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信(双向传输)——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP…

2022年下半年 软件设计师 上午试卷(前21题)

以下关于RISC&#xff08;精简指令集计算机&#xff09;特点的叙述中&#xff0c;错误的是 &#xff08;1&#xff09; 。 &#xff08;1&#xff09; A. 对存储器操作进行限制&#xff0c;使控制简单化 B. 指令种类多&#xff0c;指令功能强 C. 设置大量通用寄存器 D. 选…

【算法|动态规划No.23】leetcode376. 摆动序列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

【C#】【winform】Microsoft Visual Studio Installer Project 打包应用程序全部过程

提示&#xff1a;只针对扩展包来完成打包的工作过程。 文章目录 前言一、Microsoft Visual Studio Installer Project 是什么&#xff1f;二、安装1.安装Microsoft Visual Studio Installer Project 三、安开始打包1.添加setup1.在解决方案上面右键&#xff0c;添加-新建项目2.…

H5+Vue3编写官网,并打包发布到同一个域名下

背景 因为html5有利于搜索引擎抓取和收录我们网站更多的内容&#xff0c;对SEO很友好&#xff0c;可以为网站带来更多的流量,并且多端适配&#xff0c;兼容性和性能都非常不错&#xff0c;所以使用h5来编写官网首页。 因为用户个人中心可以通过官网跳转&#xff0c;不需要被浏…

双目视觉实战--单视图测量方法

目录 一.简介 二、2D变换 1. 等距变换&#xff08;欧式变换&#xff09; 2. 相似变换 3. 仿射变换 4. 射影变换&#xff08;透视变换&#xff09; 5. 结论 三、影消点与影消线 1. 平面上的线 2. 直线的交点 3. 2D无穷远点 4. 无穷远直线 5. 无穷远点的透视变换与仿…

【01】LVGL-CodeBlock模拟器安装 | LVGL工程下载 | PC端模拟LVGL步骤

LVGL模拟器 1.LVGL模拟器介绍2.Windows环境搭建CodeBlock及获取LVGL工程3.PC端模拟LVGL4.总结 1.LVGL模拟器介绍 LVGL模拟器&#xff1a;使用PC端软件模拟LVGL运行&#xff0c;而不需要任何嵌入式硬件。优点&#xff1a;便于学习、跨平台协同开发 2.Windows环境搭建CodeBlock及…

【Python、Qt】使用QItemDelegate实现单元格的富文本显示+复选框功能

[2023-10-19]代码已更新&#xff0c;完善了单元格宽度不足时省略号的显示问题。 [2023-10-18]代码已更新&#xff0c;追加单元格的文本对齐功能(使用成员函数QStandardItem.setTextAlignment设置单元格的Align。 主打一个 折磨 坑多 陪伴。代码为Python&#xff0c;C的就自己逐…

Python万圣节蝙蝠

目录 系列文章 前言 蝙蝠 程序设计 程序分析 运行结果 尾声 系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want5…

云务器迁移(腾讯云>华为云)

自己平时除了写些bug外还喜欢玩玩服务器&#xff0c;这不前几年买了一个域名&#xff0c;当时服务器买的是阿里云的&#xff0c;想着域名备案挺麻烦的就一直用着&#xff0c;只是在服务器到期后会重新购买其他运营商的&#xff08;关键是续不起&#x1f92b;&#xff09; 这不最…

C/C++ 快速入门

参考&#xff1a;https://blog.csdn.net/gao_zhennan/article/details/128769439 1 下载Visual Studio Code并安装中文插件&#xff0c;此处不再叙述 2 插件安装C/C插件 3 使用快捷键【Ctr ~】打打开终端 验证并未安装编译器 4 我们即将使用【MinGW-64】做为编译器 https:…

程序环境和预处理

导言&#xff1a; 在编写代码的过程中&#xff0c;我们一般都是在一些图形化软件的编译器中实现&#xff0c;编译器帮我们实现了很多操作&#xff0c;这里就一些简单的过程进行说明。本文主要阐述了c语言程序的编译链接以及一些预处理知识&#xff0c;和宏定义的使用。 目录 …

IDEA提高工作效率的实用技巧

IDEA是一款备受开发者喜爱的集成开发环境&#xff0c;它提供了许多实用的功能&#xff0c;可以帮助我们更快速、更高效地编写代码。本文将介绍一些IDEA的使用技巧提高工作效率的实用技巧。 验证正则表达式 要验证编写的正则表达式是否正确&#xff0c;只需将光标放在要检查的…

MongoDB 未授权访问漏洞

简介 MongoDB是一个基于分布式文件存储的数据库&#xff0c;是一个介于关系数据库和非关系数据库之间的产品&#xff0c;它的特点是高性能、易部署、易使用&#xff0c;存储数据非常方便&#xff0c;默认情况下是没有认证的这就导致不熟悉它的研发人员部署后没有做访问控制导致…