MySQL数据库笔记——多版本并发控制MVCC

news2025/4/28 10:09:28

大家好,这里是Good Note,关注 公主号:Goodnote,本文详细介绍MySQL的并发控制:多版本并发控制MVCC。

在这里插入图片描述

文章目录

    • 背景介绍
      • 数据库并发控制——锁机制
        • 悲观锁和乐观锁
          • 悲观锁
          • 乐观锁
      • 数据库并发控制——MVCC 的引入
      • MVCC 和锁机制的对比
    • MySQL 的多版本并发控制 (MVCC)
      • 快照读和当前读
      • 快照读和当前读的对比
      • 隐藏的系统列
      • Undo Log(回滚日志)
      • Read View(读视图)
      • 可见性算法(Visibility Algorithm)
      • MVCC 支持的事务隔离级别
      • 整体工作流程
      • 总结
      • MVCC 的优点
      • MVCC 的局限性
      • 示例:MVCC 的快照读
    • 历史文章

背景介绍

许多人认为 MVCC(Multi-Version Concurrency Control,多版本并发控制) 是一种乐观锁的实现方式,我们先来了解一下什么是乐观锁和悲观锁。

数据库并发控制——锁机制

在数据库系统中,并发控制是保证多个事务在并发执行时数据一致性的核心技术。传统的并发控制方法是使用 ,它是一种直接而有效的解决方案。

  • 锁的分类
    • DQL(Data Query Language,数据查询语言):查询数据(如 SELECT)时使用 读锁
    • DML(Data Manipulation Language,数据操作语言):对数据进行增、删、改操作(如 INSERTDELETEUPDATE)时使用 写锁
    • DDL(Data Definition Language,数据库定义语言):定义和修改表结构(如 CREATE TABLEDROP TABLE)时,通常会使用 元数据锁
悲观锁和乐观锁
悲观锁
  • 概念
    悲观锁假定会发生并发冲突,因此在对资源进行操作之前,会先加锁,确保其他事务无法同时访问该资源。
  • 特点
    • 需要加锁,锁定资源后,其他线程对该资源的操作会被阻塞。
    • 开销较大,可能导致性能下降。
  • 应用场景
    • 适用于并发冲突频繁的场景。
  • 例子
    数据库中的 行级锁 或 Java 中的 synchronized 关键字。
乐观锁
  • 概念
    乐观锁假定不会发生并发冲突,因此不加锁,而是在更新数据时,通过比较版本号或条件检查来保证操作的正确性。
  • 特点
    • 不加锁,操作更轻量级。
    • 需要在操作完成后检查是否发生冲突。
  • 应用场景
    • 适用于并发冲突较少的场景。
  • 实现方式
    • 版本号机制:每次修改数据时,更新版本号。更新操作成功的前提是版本号没有变化。
    • CAS(Compare And Swap):通过原子性比较和更新操作实现乐观锁。

数据库并发控制——MVCC 的引入

许多人认为 MVCC(Multi-Version Concurrency Control,多版本并发控制) 是一种乐观锁的实现方式,但 MVCC 的核心在于通过 版本控制和可见性算法 来实现数据库的并发控制。InnoDB 的 MVCC 通过隐藏字段、Undo Log 和 Read View 协同工作,实现了高效的多版本并发控制:

  1. 隐藏字段

    • 提供版本控制信息,判断事务的可见性。
  2. Undo Log

    • 保存数据的历史版本,支持事务回滚和快照读。
  3. Read View

    • 在事务启动时生成的元数据,用于确定哪些数据版本对事务可见。

MVCC 和锁机制的对比

特性锁(悲观锁/乐观锁)MVCC
加锁开销悲观锁需要加锁,开销较大;乐观锁无需加锁不加锁,依赖多版本数据
并发性能读写互斥,可能导致线程阻塞读写分离,读操作不阻塞写
实现方式直接加锁或通过版本号/CAS 判断通过 Undo Log 和事务视图维护多版本
适用场景并发冲突频繁的场景(悲观锁)读多写少的场景,且冲突较少
优缺点加锁开销大,读写冲突会阻塞空间开销较大,但读性能更优

MySQL 的多版本并发控制 (MVCC)

多版本并发控制 (MVCC, Multi-Version Concurrency Control) 是 MySQL 用于实现事务隔离的一种机制,主要应用于 InnoDB 存储引擎。通过 MVCC,MySQL 可以在高并发环境下实现 读写并行,同时减少锁的使用,提高性能。

快照读和当前读

  • 快照读(Snapshot Read)

    • 读取的是数据的快照版本(历史版本),即事务开始时的数据状态,而不是最新的
    • 常见的 SELECT 语句都是快照读,除非显式使用加锁查询。
  • 当前读(Current Read)

    • 读取的是最新版本的数据,并且会对读取的数据加锁以确保一致性
    • 常见的当前读操作包括:
      • SELECT ... FOR UPDATE
      • SELECT ... LOCK IN SHARE MODE
      • UPDATE
      • DELETE
      • INSERT

快照读和当前读的对比

操作类型快照读(Snapshot Read)当前读(Current Read)
使用场景普通 SELECT 查询加锁查询(SELECT ... FOR UPDATE 等)
是否加锁不加锁加锁
数据版本读取快照版本,使用 Undo Log读取当前版本,可能会阻塞
是否支持 MVCC支持支持,但需要额外的锁操作

隐藏的系统列

InnoDB 存储引擎会为每一行记录添加了以下 三个隐藏的系统列,用于实现 MVCC:

isDeleteDB_TRX_IDDB_ROLL_PTRRowID(可选)idnamepassword
是否删除事务 ID回滚指针隐藏的自增 ID。如果表未指定主键,系统会自建idnamepassword
字段名含义
isDelete标记该记录是否被逻辑删除,删除标志不是单独的字段,而是存储在记录头信息中,用户不可见。
DB_TRX_ID记录每行数据最近一次修改(插入/更新)所对应的事务 ID(Read View中的事务ID)。
DB_ROLL_PTR回滚指针,指向该记录的 undo log 日志,保存行的历史版本。

Undo Log(回滚日志)

Undo Log 是 InnoDB 存储引擎用于实现事务回滚、快照读(MVCC)的重要机制之一。它记录数据修改前的旧版本,并通过回滚指针(DB_ROLL_PTR)形成一条 Undo 日志链。

  • 功能

    1. 事务回滚
      • 当事务未提交或被回滚时,Undo Log 提供修改前的数据,用于恢复到原始状态,撤销未提交事务对数据库的影响。
    2. 多版本控制(MVCC)
      • Undo Log 保存了数据的历史版本,通过回滚指针(DB_ROLL_PTR),其他事务可以通过 Undo Log 获取旧版本数据。
  • Undo Log 的特性

    • 逻辑日志
      • 记录逻辑上的操作。例如:
        • 删除一条记录时,Undo Log 会记录一个对应的“插入操作”。
        • 更新一条记录时,Undo Log 会记录一个对应的“反向更新操作”。
    • 存储位置
      • Undo Log 存储在 回滚段 中。
  • Undo Log 的分类

    1. Insert Undo Log
      • 记录事务插入数据时的日志。
      • 特点:事务提交后即可丢弃,因为没有其他事务需要访问它。
    2. Update Undo Log
      • 记录事务更新或删除数据时的日志。
      • 特点:事务提交后,仍需保留以支持快照读,只有当没有比该日志更早的 Read View 存在时,才能删除。
  • 问题与优化

    • 长事务可能导致 Undo Log 无法及时清理,因为较早的 Read View 仍然需要访问旧版本数据。这会导致存储空间占用过大,建议避免长时间未提交的事务。

Read View(读视图)

Read View 是事务在执行快照读(Snapshot Read)时生成的一种快照机制,用于判断当前事务对哪些数据版本可见。

  • 功能

    • Read View 确保事务在快照读时能够看到一致性的数据。
    • 通过可见性算法(Visibility Algorithm)判断某个数据版本是否对当前事务可见。
  • Read View 的组成

    1. alive_trx_list
      • 当前系统中活跃的事务 ID 列表,包含所有未提交事务的 ID。
    2. up_limit_id
      • alive_trx_list 中的最小事务 ID。
    3. low_limit_id
      • 系统当前分配的最大事务 ID 加 1。

可见性算法(Visibility Algorithm)

在生成 Read View 后,InnoDB 通过以下步骤判断数据版本(DB_TRX_ID)是否对当前事务可见, MVCC 的可重复读(Repeatable Read)隔离级别判断如下:

  1. 判断是否早于活跃事务的最小 ID

    • 如果 DB_TRX_ID < up_limit_id,表明该版本在生成 Read View 前已提交,对当前事务可见。
  2. 判断是否晚于最新事务的最大 ID

    • 如果 DB_TRX_ID >= low_limit_id,表明该版本在生成 Read View 后才生成,对当前事务不可见。
  3. 判断是否属于活跃事务

    • 如果 DB_TRX_IDalive_trx_list 中,说明生成 Read View 时该事务仍未提交,因此该版本对当前事务不可见。
  4. 通过回滚指针查找可见版本

    • 如果数据版本不可见且 ROLL_PTR 不为空,则通过 ROLL_PTR 指向的 Undo Log 查找更早的版本,重复上述判断,直到找到可见的版本。

MVCC 支持的事务隔离级别

1. 读未提交(Read Uncommitted)

  • Read View

    • 不使用 Read View。
    • 读取数据时直接读取最新版本,无论数据是否由其他事务提交。
  • 可见性规则

    • 所有事务的最新修改版本对当前事务可见
    • 即使其他事务未提交的数据,也可以被读取(会发生脏读)。
  • 特点

    • 无需 Undo Log,也不使用 alive_trx_list 等 Read View 属性。

2. 读已提交(Read Committed)

  • Read View

    • 每次查询都会生成新的 Read View,因此每次查询的结果可能不同
    • Read View 只在当前查询的上下文中生效,不跨查询复用。
  • 可见性规则

    1. 如果 DB_TRX_ID 小于 up_limit_id(即数据版本在当前查询的 Read View 生成之前已提交),则该版本对当前事务可见
    2. 如果 DB_TRX_ID 在活跃事务列表中,说明该版本由未提交事务生成,对当前事务不可见
  • 特点

    • 数据版本的可见性随着每次查询变化。
    • 防止脏读,但可能发生不可重复读。

3. 可重复读(Repeatable Read)

  • Read View

    • 事务开始时生成一次 Read View,整个事务期间使用同一个快照,确保读取结果一致
    • 该 Read View 的属性(up_limit_idlow_limit_idalive_trx_list)在事务期间不会变化。
  • 可见性规则

    1. 如果 DB_TRX_ID < up_limit_id,说明数据版本在事务开始前已提交,对当前事务可见
    2. 如果 DB_TRX_ID >= low_limit_id,说明数据版本在事务开始后生成,对当前事务不可见
    3. 如果 DB_TRX_IDalive_trx_list 中,说明数据版本由未提交的事务生成,对当前事务不可见
  • 特点

    • 读操作始终基于事务开始时生成的 Read View。
    • 防止脏读和不可重复读,但可能发生幻读。

4. 串行化(Serializable)

  • Read View

    • 不使用 Read View。
    • 通过加锁(如共享锁、排他锁)实现事务隔离。
  • 可见性规则

    • 每次读取时都会加锁,确保当前读操作的可见性。
    • 因为加锁阻塞了其他事务的修改或读取,因此不存在不可见的问题。
  • 特点

    • 防止脏读、不可重复读和幻读。
    • 并发性能较低,但数据一致性最高。

整体工作流程

  1. 事务修改数据时

    • 写入 Undo Log,保存旧版本数据。
    • 更新 DB_TRX_IDDB_ROLL_PTR
  2. 事务执行快照读时

    • 生成 Read View,记录当前系统中活跃事务列表。
    • 判断数据版本是否可见:
      • 若不可见,使用 DB_ROLL_PTR 查找历史版本。
  3. 事务提交时

    • Insert Undo Log 可直接删除。
    • Update Undo Log 保留,用于支持其他事务的快照读。
  4. 事务回滚时

    • 通过 Undo Log 恢复旧版本数据,撤销事务的影响。

总结

  • MVCC 是 InnoDB 存储引擎中实现事务隔离和提高并发性能的关键机制

  • 通过维护多个数据版本和 Undo Log,实现快照读和当前读,避免了大量加锁操作。

  • Undo Log

    • 是 MVCC 的基础,记录旧版本数据,支持事务回滚和快照读。
    • 分类为 Insert Undo Log 和 Update Undo Log。
  • Read View

    • 确保快照读的隔离性,通过可见性算法判断数据版本是否可见。
    • 隔离级别的不同会影响 Read View 的生成时机。
  • 两者配合

    • Undo Log 提供数据的历史版本,Read View 判断哪些版本对当前事务可见,共同实现事务的并发控制和一致性。

MVCC 的优点

  1. 提高并发性能

    • 快照读不需要加锁,避免了读写之间的冲突。
  2. 减少锁开销

    • 大量读操作可以通过读取历史版本完成,无需加锁,提高效率。
  3. 支持事务隔离

    • MVCC 能够在不同的隔离级别下提供一致的数据读取。

MVCC 的局限性

  1. 占用存储空间

    • Undo Log 的存在会增加存储开销,特别是长事务会导致 Undo Log 增长。
  2. 长事务的性能问题

    • 长事务可能会导致 Undo Log 不能被及时清理,增加性能开销。
  3. 仅适用于读写混合场景

    • 如果事务中大量是写操作,MVCC 的优势会减弱,因为写操作仍需加锁。

示例:MVCC 的快照读

1. 表结构

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    status VARCHAR(20)
);

2. 插入数据

INSERT INTO orders (status) VALUES ('pending'), ('shipped'), ('delivered');

3. 启动事务并模拟并发查询
事务 A:

START TRANSACTION;
SELECT * FROM orders; -- 快照读,读取事务开始时的版本
UPDATE orders SET status = 'cancelled' WHERE id = 1; -- 当前读,修改最新版本

事务 B:

START TRANSACTION;
SELECT * FROM orders WHERE id = 1; -- 读取事务 A 修改前的快照版本

结果:

  • 事务 A 在事务 B 提交之前,可以看到修改后的状态。
  • 事务 B 在事务 A 提交之前,读取的是修改前的状态。

历史文章

  1. MySQL数据库笔记——数据库三范式
  2. MySQL数据库笔记——存储引擎(InnoDB、MyISAM、MEMORY、ARCHIVE)
  3. MySQL数据库笔记——常见的几种锁分类
  4. MySQL数据库笔记——索引介绍
  5. MySQL数据库笔记——事务介绍
  6. MySQL数据库笔记——索引结构之B+树
  7. MySQL数据库笔记——索引潜规则(回表查询、索引覆盖、索引下推)
  8. MySQL数据库笔记——索引潜规则(最左前缀原则)
  9. MySQL数据库笔记——常见慢查询优化方式
  10. MySQL数据库笔记——日志介绍

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

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

相关文章

css3实现文字下滑波浪线

上效果 上菜 text-decoration 属性作用&#xff1a;用于设置或检索文本的装饰线&#xff0c;如下划线、上划线、删除线等 text-decoration: line || color || style; 参数&#xff1a; line: 指定装饰线类型&#xff0c;如 underline&#xff08;下划线&#xff09;、overline&…

Springboot 3项目整合Knife4j接口文档(接口分组详细教程)

文章目录 前言一、Spring Boot 3.0整合Knife4j二、OpenApi 3注解的使用规范三、使用步骤 1.Spring Boot 3.0项目中使用knife4j2.在application.yml中添加knife4j相关配置3.设置WebMvc相关配置&#xff08;解决封装统一异常处理后doc.html无法打开的问题&#xff09;4.创建Knif…

2024年中国新能源汽车用车发展怎么样 PaperGPT(一)

概述 在国家政策的强力扶持下&#xff0c;2024年中国新能源汽车市场迎来了新的发展机遇。本文将基于《中国新能源汽车用车报告&#xff08;2024年&#xff09;》的数据&#xff0c;对新能源汽车的市场发展和用车趋势概述。 新能源汽车市场发展 政策推动&#xff1a;国家和地…

华三交换机如何进行堆叠?

准备&#xff1a;两台交换机堆叠 1、进行连线 2、交换机都选取 FortyGigE1/0/53 和 FortyGigE1/0/54 做 堆叠口 配置&#xff1a;进行交换机配置 X_T1_Core_1&#xff1a; [X_T1_Core_1]irf domain 0 //同一拓扑内如果有其它堆叠组&#xff0c;domain不能重复 [X_T1_Core_1]…

活动预告 | Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁

课程介绍 通过 Microsoft Learn 免费参加 Microsoft 安全在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft Cloud 技术的了解。参加我们举办的“通过扩展检测和响应抵御威胁”技术公开课活动&#xff0c;了解如何更好地在 Microsoft 365 Defen…

Sonic:开源Go语言开发的高性能博客平台

Sonic&#xff1a;一个用Go语言开发的高性能博客平台 简介 Sonic&#xff0c;一个以其速度如声速般快速而命名的博客平台&#xff0c;是一个用Go语言开发的高性能博客系统。正如其名字所暗示的&#xff0c;Sonic旨在提供一个简单而强大的博客解决方案。这个项目受到了Halo项目…

大模型WebUI:Gradio全解系列8——Additional Features:补充特性(上)

大模型WebUI&#xff1a;Gradio全解系列8——Additional Features&#xff1a;补充特性&#xff08;上&#xff09; 前言本篇摘要8. Additional Features&#xff1a;补充特性8.1 队列8.1.1 使用方法8.1.2 配置队列演示 8.2 输入输出流8.2.1 输出流1. 生成器yield2. 流媒体 8.2…

音视频入门基础:MPEG2-PS专题(4)——FFmpeg源码中,判断某文件是否为PS文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.ps 可以判断出某个文件是否为PS文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为PS文件呢&#xff1f;它内部其实是通过mpegps_probe函数来判断的。从《FFmpeg源码&#xff1a;av_probe_input_format3函数和AVI…

【Leetcode】3280. 将日期转换为二进制表示

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个字符串 date&#xff0c;它的格式为 yyyy-mm-dd&#xff0c;表示一个公历日期。 date 可以重写为二进制表示&#xff0c;只需要将年、月、日分别转换为对应的二进制表示&a…

Spring实现输出带动态标签的日志

版权说明&#xff1a; 本文由博主keep丶原创&#xff0c;转载请保留此块内容在文首。 原文地址&#xff1a; https://blog.csdn.net/qq_38688267/article/details/144851857 文章目录 背景底层原理实现方案Tag缓存实现封装注解通过AOP实现日志缓存封装行为参数通用方法实现手动…

JAVA: 状态模式(State Pattern)的技术指南

1、简述 状态模式是一种行为型设计模式,允许对象在其内部状态改变时改变其行为。它将状态相关的行为抽取到独立的状态类中,使得增加新状态变得简单,且不影响其他状态。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 本文将详细介绍状态模式的概念…

小程序基础 —— 02 微信小程序账号注册

微信小程序账号注册 小程序开发与网页开发不一样&#xff0c;在开始微信小程序开发之前&#xff0c;需要访问微信公众平台&#xff0c;注册一个微信小程序账号。 有了小程序的账号以后&#xff0c;才可以开发和管理小程序&#xff0c;后续需要通过该账号进行开发信息的设置、…

安卓入门十一 常用网络协议四

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09; MQTT是一种轻量级的、发布/订阅模式的消息传输协议。它被设计用于在低带宽或不稳定网络环境下&#xff0c;实现物联网设备之间的可靠通信。 4.1 MQTT详细介绍 发布/订阅模式&#xff1a;MQTT 使用发布/订…

在 Swift 中使用 SQL 组合人员和地址数据

文章目录 摘要描述问题描述示例输入与输出 Swift 代码解决方案代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在本篇文章中&#xff0c;我们将讨论如何结合两个表——Person 和 Address&#xff0c;以便生成包含每个人的姓名和地址信息的结果表。如果某人的地址信息不…

AAL省电效果对比

AAL省电的原理主要是‌通过根据显示内容来降低背光&#xff0c;然后通过调节gamma来补偿显示亮度&#xff0c;从而达到省电的效果‌。具体来说&#xff0c;gamma值越高&#xff0c;灰度越低&#xff0c;图像越暗。因此&#xff0c;颜色越暗的图片越省电&#xff0c;这也是为什么…

ArcGIS中怎么进行水文分析?(思路介绍)

最近有人咨询&#xff0c;ArcGIS中怎么进行水文分析&#xff0c;大致的说一下河网提取的思路哈 解决思路&#xff1a;dem填洼→计算水流方向→计算水流累积矩阵→形成河网 dem填洼 计算水流方向 计算水流累积矩阵 用栅格计算器&#xff0c;设阈值&#xff08;自己多次尝试&…

Debian-linux运维-ssh配置(兼容Jenkins插件的ssh连接公钥类型)

系统版本&#xff1a;Debian 12.5、11.1 1 生成密钥对 可以用云服务商控制台生成的密钥对&#xff0c;也可以自己在客户端或者服务器上生成&#xff0c; 已经有密钥对就可以跳过这步 用户默认密钥文件路径为 ~/.ssh/id_rsa&#xff0c;可以在交互中指定路径&#xff0c;也可…

ZZNUOJ 1798:大小写判断(C/C++/Java)

题目描述 给定一个英文字母判断这个字母是大写还是小写。 输入 输入只包含一个英文字母c。 输出 如果c是大写字母,输出“upper”,否则输出“lower”。 样例输入 x 样例输出 lower 来源 蓝桥杯算法训练 常见的ASCII值 ASCII表中可以记下部分特殊的值(十进制)(字母从A到Z&am…

Wonder Dynamics技术浅析(二):人体姿态估计

Wonder Dynamics 的人体姿态估计模块旨在从图像或视频中检测并定位人体关键点&#xff08;如关节、肢体等&#xff09;&#xff0c;为后续的动作捕捉、虚拟角色动画等应用提供基础数据。 一、人体姿态估计概述 人体姿态估计是指从图像或视频中检测并定位人体关键点的位置&…

前端压缩字体包方法,8MB可压缩至900K!

1、先安装压缩工具 npm install font-spider -g2、新建个文件夹&#xff0c;把要压缩的字体放进去&#xff0c;然后新建一个html&#xff0c;如下图 目前没有经过压缩的字体包是接近8MB 新建的html内容如下&#xff0c;直接复制即可 解释&#xff1a; 1、在样式中定义要压缩…