MVCC理解

news2025/6/6 14:19:16

MySQL的MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种高效的并发控制机制,通过维护数据的多个版本实现读写操作的并行执行,显著提升数据库的并发性能和数据一致性。

MVCC 的实现依赖于:隐藏字段、Read View、undo log

隐藏字段

  • DB_TRX_ID(6字节):表示最后一次插入或更新该行的事务 id。此外,delete 操作在内部被视为更新,只不过会在记录头 Record header 中的 deleted_flag 字段将其标记为已删除
  • DB_ROLL_PTR(7字节): 回滚指针,指向该行的 undo log如果该行未被更新,则为空
  • DB_ROW_ID(6字节):如果没有设置主键且该表没有唯一非空索引时,InnoDB 会使用该 id 来生成聚簇索引

Read View

ReadView(读视图)是 InnoDB 为了实现一致性读(Consistent Read)而创建的数据结构,它用于确定在特定事务中哪些版本的行记录是可见的。

当事务开始执行时,InnoDB 会为该事务创建一个 ReadView,这个 ReadView 会记录 4 个重要的信息:

  • creator_trx_id:创建该 ReadView 的事务 ID。

  • m_ids:所有活跃事务的 ID 列表,活跃事务是指那些已经开始但尚未提交的事务。

  • min_trx_id:所有活跃事务中最小的事务 ID。它是 m_ids 数组中最小的事务 ID。

  • max_trx_id:事务 ID 的最大值加一。换句话说,它是下一个将要生成的事务 ID。

Undo log

undo log(回滚日志) 主要有两个作用:

  • 当事务回滚时用于将数据恢复到修改前的样子
  • 另一个作用是 MVCC ,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读

InnoDB 存储引擎中 undo log 分为两种:insert undo logupdate undo log

  1. insert undo log:指在 insert 操作中产生的 undo log。因为 insert 操作的记录只对事务本身可见,对其他事务不可见,故该 undo log 可以在事务提交后直接删除。不需要进行 purge 操作
  2. update undo logupdatedelete 操作中产生的 undo log。该 undo log可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge线程 进行最后的删除

可见性判断

当读取一行数据时,会通过以下规则判断该版本是否可见:

  • 如果该版本的DB_TRX_ID小于min_trx_id,说明该版本在创建ReadView时已经提交,可见
  • 如果该版本的DB_TRX_ID大于等于max_trx_id,说明该版本在创建ReadView时还未开始,不可见
  • 如果该版本的DB_TRX_ID在m_ids中,说明该版本在创建ReadView时还未提交,不可见
  • 如果该版本的DB_TRX_ID等于creator_trx_id,说明该版本是当前事务修改的,可见

可见性判断举例

前景知识

事务开始和ReadView创建的时序关系:

  1. 事务开始
    1. 当执行 BEGIN 或 START TRANSACTION 时,事务开始
    2. 此时会分配一个事务ID(trx_id)
    3. 但此时并不会创建ReadView
  2. ReadView创建
    1. ​​​​​在第一次执行SELECT语句时才会创建ReadView
    2. 不同隔离级别下,ReadView的创建时机不同:
      • READ COMMITTED:每次SELECT都会创建新的ReadView
      • REPEATABLE READ:第一次SELECT时创建ReadView,后续复用

假设我们有一个用户表,包含以下数据:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT
);

INSERT INTO users VALUES (1, '张三', 20);

场景1:事务ID小于min_trx_id(已提交事务)

事务1 (trx_id=100): 开始事务
事务2 (trx_id=101): 开始事务
事务1: 更新 users 表,将张三的年龄改为21
事务1: 提交事务
事务2: 创建ReadView (min_trx_id=101, max_trx_id=102, m_ids=[101])
事务2: 读取 users 表

结果:事务2可以看到更新后的数据(年龄=21)

原因:因为事务1的trx_id(100) < min_trx_id(101),说明该版本在创建ReadView时已经提交

 场景2:事务ID大于等于max_trx_id(未开始事务)

事务1 (trx_id=100): 开始事务
事务1: 创建ReadView (min_trx_id=100, max_trx_id=101, m_ids=[100])
事务2 (trx_id=101): 开始事务
事务2: 更新 users 表,将张三的年龄改为22
事务1: 读取 users 表

结果:事务1看不到事务2的更新(仍然看到年龄=20)

原因:因为事务2的trx_id(101) >= max_trx_id(101),说明该版本在创建ReadView时还未开始

 场景3:事务ID在m_ids中(未提交事务)

事务1 (trx_id=100): 开始事务
事务2 (trx_id=101): 开始事务
事务1: 更新 users 表,将张三的年龄改为21
事务2: 创建ReadView (min_trx_id=100, max_trx_id=102, m_ids=[100,101])
事务2: 读取 users 表

 

结果:事务2看不到事务1的更新(仍然看到年龄=20)

原因:因为事务1的trx_id(100)在m_ids中,说明该版本在创建ReadView时还未提交

 场景4:事务ID等于creator_trx_id(当前事务修改)

事务1 (trx_id=100): 开始事务
事务1: 创建ReadView (min_trx_id=100, max_trx_id=101, m_ids=[100])
事务1: 更新 users 表,将张三的年龄改为21
事务1: 读取 users 表

 

结果:事务1可以看到自己的更新(看到年龄=21)

原因:因为该版本的trx_id(100)等于creator_trx_id(100),说明该版本是当前事务修改的

隔离级别与MVCC

 ​​1. 读未提交(Read Uncommitted)​

  • ​MVCC 行为​​:​​不使用 MVCC​​,直接读取数据的最新版本(包括未提交的数据)。
  • ​数据可见性​​:事务可看到其他事务未提交的修改(脏读)。
  • ​典型问题​​:脏读、不可重复读、幻读均可能发生。
  • ​适用场景​​:对数据一致性要求极低的场景(如日志记录)。

 ​​2. 读已提交(Read Committed)​

  • ​MVCC 行为​​:
    • ​每次 SELECT 生成新 ReadView​​:每次查询时创建新的快照,仅读取已提交的数据版本。
    • ​写操作使用当前读​​:UPDATE/DELETE 操作会读取最新已提交数据并加锁。
  • ​数据可见性​​:事务内多次查询可能看到不同结果(因其他事务提交导致数据变更)。
  • ​解决的问题​​:脏读(因只读已提交数据)。
  • ​未解决的问题​​:不可重复读、幻读(因无间隙锁)。
  • ​适用场景​​:需避免脏读,但允许不可重复读的场景(如实时统计)。

​3. 可重复读(Repeatable Read,MySQL 默认级别)​

  • ​MVCC 行为​​:
    • ​事务开始时生成固定 ReadView​​:整个事务复用同一快照,确保多次查询结果一致。
    • ​通过版本链访问历史数据​​:通过 DB_ROLL_PTR 回溯旧版本。
  • ​锁机制补充​​:​​间隙锁(Gap Lock)​​ 阻止范围内新数据插入,解决幻读。
  • ​解决的问题​​:脏读、不可重复读、幻读(InnoDB 通过 MVCC + 间隙锁实现)。
  • ​适用场景​​:需保证事务内数据一致性的场景(如账户余额查询)。

4. 串行化(Serializable)​

  • ​MVCC 行为​​:​​基本不使用 MVCC​​,主要依赖严格的锁机制(读写均加锁)。
  • ​数据可见性​​:事务串行执行,完全隔离并发操作。
  • ​解决的问题​​:所有并发问题(脏读、不可重复读、幻读)。
  • ​缺点​​:​​性能最低​​,高并发下易引发锁等待和死锁。
  • ​适用场景​​:对数据一致性要求极高且并发量低的场景(如金融清算)。
  • 读未提交(Read Uncommitted):不使用MVCC,直接读取数据的最新版本(包括未提交的数据),脏读、不可重复读、幻读均可能发生。
  • 读已提交(Read Committed)​:使用MVCC
  • 可重复读(Repeatable Read,MySQL 默认级别)​
  • 串行化(Serializable)​

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

705SJBH超市库存管理系统文献综述

前言 信息化的发展已经对我们的日常生活产生了积极的影响&#xff0c;无论是企业、商店、机关、甚至个人&#xff0c;每天都面对着大量的信息&#xff0c;而如果能有效地识别有用信息&#xff0c;并在对它们加工的基础上充分的利用信息&#xff0c;无疑会给我们的生活带来很巨…

shell:基础

本文主要探讨shell相关知识。 变量 $? 上一次执行命令返回状态 $$ 当前进程进程号 $! 后台运行的最后一个进程的进程号 $# 位置参数的数量 $* 参数内容 $ 参数内容 $和$*解析"hello word"为"hello" "word" "$"解析"hello word&…

【JVM】万字总结GC垃圾回收

【JVM】GC垃圾回收 概念 在程序运行过程中&#xff0c;会不断创建对象来使用内存&#xff0c;当这些对象不再被引用时&#xff0c;其所占用的内存若不及时释放&#xff0c;会导致内存占用不断增加&#xff0c;最终可能引发内存溢出。GC 机制能自动检测并回收这些不再使用的对…

内网横向之RDP缓存利用

RDP&#xff08;远程桌面协议&#xff09;在连接过程中会缓存凭据&#xff0c;尤其是在启用了 "保存密码" 或 "凭据管理器" 功能时。这个缓存的凭据通常是用于自动填充和简化后续连接的过程。凭据一般包含了用户的用户名和密码信息&#xff0c;或者是经过加…

【Linux网络】传输层TCP协议

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12891150.html 目录 TCP 协议 TCP 协议段格式 确认应答(ACK)机制 超时重传机制 连接管理机制 …

不同视角理解三维旋转

在二维空间中&#xff0c;绕任意点旋转可以分解为&#xff1a; 1&#xff09;平移旋转点到原点&#xff0c;2&#xff09;绕原点旋转&#xff0c;3&#xff09;逆平移旋转点&#xff1b; 可用矩阵表示为 &#xff0c; 其中&#xff0c; 表示绕原点旋转 &#xff0c; 为平移矩…

Adobe Acrobat——设置PDF打印页面的大小

1. 打开 PDF 文件&#xff1b; 2. 点击菜单栏的 “文件” → “打印”&#xff1b; 3. 在打印对话框中&#xff0c;点击 “属性”&#xff1b; 4. 点击 “布局”→ “高级”&#xff1b; 5. 点击 “纸张规格”&#xff0c;选择 “PostScript 自定义页面大小”&#xff0c;然后…

Android apk装机编译类型: verify、speed-profile, speed与启动耗时

Android apk装机编译类型: verify、speed-profile, speed与启动耗时 Dex2oat (dalvik excutable file to optimized art file) &#xff0c;对 dex 文件进行编译优化&#xff0c;Android 虚拟机可识别的是dex文件&#xff0c;应用运行过程如果每次都将dex文件加载内存&#xff…

使用Virtual Serial Port Driver+com2tcp(tcp2com)进行两台电脑的串口通讯

使用Virtual Serial Port Drivercom2tcp或tcp2com进行两台电脑的串口通讯 问题说明解决方案方案三具体操作流程网上教程软件安装拓扑图准备工作com2tcp和tcp2com操作使用串口助手进行验证 方案三存在的问题数据错误通讯延时 问题说明 最近想进行串口通讯的一个测试&#xff0c…

数智破局·生态共生:重构全球制造新引擎 2025 WOD制造业数字化博览会即将在沪盛大启幕

共探数智化未来&#xff0c;共创新质生产力。2025年6月17日—19日&#xff0c;上海浦东新国际博览中心将迎来全球制造业数字化转型的盛会——WOD制造业数字化博览会。作为全球首个聚焦制造业数字化全场景的专业展会&#xff0c;本届展会以“数智破局生态共生&#xff1a;重构全…

BGP/MPLS IP VPN跨域解决方案

目录 MPLS VPN跨域方案出现背景: MPLS VPN回顾 VRF(Virtual Route Forward)虚拟路由转发 MPLS(Multiple Protcol Label Swtich)多协议标签交换 MP-BGP多协议BGP MPLS VPN跨域OptionA 控制平面: 转发平面: 总结: 挑战: MPLS VPN跨域OptionB 非RR场景: 控制平面: 转发…

backend 服务尝试连接 qdrant 容器,但失败了,返回 502 Bad Gateway 问题排查

遇到的问题是&#xff1a; backend 报错&#xff1a;502 Bad Gateway 来自 Qdrant → 导致接口 /api/chat 返回 500 Internal Server Error并且日志中提示&#xff1a; QDRANT_URL http://qdrant:6333✅ 问题分析 这个错误的根本原因是&#xff1a; 你的 backend 服务尝试连…

18. Qt系统相关:多线程

一、概述 在Qt中&#xff0c;使用QThread类对系统线程进行了封装。QThread代表一个在应用程序中可独立控制的线程&#xff0c;也可以和进程中的其他线程共享数据。 二、QThread常用API 三、QThread使用 自定义一个类&#xff0c;继承自QThread&#xff0c;并且只有一个线程处…

6个月Python学习计划 Day 14 - 异常处理基础( 补充学习)

第二周 Day 8 - Python 函数基础 Day 9 - 函数进阶用法 Day 10 - 模块与标准库入门 Day 11 - 列表推导式、内置函数进阶、模块封装实战 Day 12 - 字符串处理 & 文件路径操作 Day 13 - 文件操作基础 &#x1f3af; 今日目标 理解异常的概念和常见异常类型掌握 try-except …

使用jstack排查CPU飙升的问题记录

最近&#xff0c;看到短视频传播了一个使用jstack来协助排查CPU飙升的案例。我也是比较感兴趣&#xff0c;参考了视频博主的流程&#xff0c;自己做了下对应案例的实战演练&#xff0c;在此&#xff0c;想做一下&#xff0c;针对相关问题模拟与排查演练的实战过程记录。 案例中…

cursor如何开启自动运行模式

在Cursor中&#xff0c;开启自动运行模式即启用“Yolo Mode”&#xff0c;具体操作如下&#xff1a; 按下Ctrl Shift J&#xff08;Windows/Linux&#xff09;或Cmd Shift J&#xff08;Mac&#xff09;打开Cursor设置。导航到“Features”&#xff08;功能&#xff09;选…

SecureCRT 设置超时自动断开连接时长

我们在使用SecureCRT 连接服务器时&#xff0c;经常性出现2分钟未操作已连接的服务器&#xff0c;就会自动断开连接&#xff0c;此时需要重新连接&#xff0c;非常影响服务器操作&#xff0c;本文可以很好带领大家解决这种问题。

IEC 61347-1:2015 灯控制装置安全标准详解

IEC 61347-1:2015灯控制装置安全标准详解 IEC 61347-1:2015 是国际电工委员会&#xff08;IEC&#xff09;发布的灯控制装置第1部分&#xff1a;通用要求和安全要求的核心标准&#xff0c;为各类照明用电子控制设备设定了全球通用的安全基准。该标准适用于独立式或内置于灯具/…

Ansys Zemax | 手机镜头设计 - 第 4 部分:用 LS-DYNA 进行冲击性能分析

附件下载 联系工作人员获取附件 该系列文章将讨论智能手机镜头模组设计的挑战&#xff0c;从概念和设计到制造和结构变形分析。本文是四部分系列中的第四部分&#xff0c;它涵盖了相机镜头的显式动态模拟&#xff0c;以及对光学性能的影响。使用 Ansys Mechanical 和 LS - DY…

[蓝桥杯]卡片换位

卡片换位 题目描述 你玩过华容道的游戏吗&#xff1f; 这是个类似的&#xff0c;但更简单的游戏。 看下面 3 x 2 的格子 --------- | A | * | * | --------- | B | | * | --------- 在其中放 5 张牌&#xff0c;其中 A 代表关羽&#xff0c;B 代表张飞&#xff0c;* …