当前位置: 首页 > article >正文

Mysql高级篇(中)——多版本并发控制 MVCC

多版本并发控制 MVCC

  • 一、概述
  • 二、基本原理
  • 三、实现原理
  • 四、示例解释
  • 五、MVCC 优点
  • 六、现实中的实现
  • 七、MVCC 三剑客
    • 1. ReadView
    • 2. Undo Log
    • 3. Purge
    • 4. 三者之间的关系:
    • 5. 示例
    • 6. 总结
  • 八、MVCC 整体操作流程
  • ⭐、readview
    • 1. 作用
    • 2. 工作机制
    • 3. 数据版本的可见性判断规则
    • 4. 应用场景
    • 5. 示例
    • 6. 总结
  • ⭐、隐藏字段

一、概述

多版本并发控制MVCC,Multi-Version Concurrency Control)是一种用于管理数据库系统中并发事务的技术,主要目的是在多个事务同时执行时,提供一致性读操作并避免冲突。它通过为每个事务创建不同的“数据版本”,实现读写并发,从而使得读操作不会阻塞写操作,反之亦然。

二、基本原理

MVCC系统中,每次事务对数据进行修改时,数据库会为数据生成一个新的版本,而不是直接覆盖旧的版本。这样,旧版本的数据仍然保留,用于满足并发读请求。每个事务在读取数据时,能够根据其开始的时间戳看到与其一致的版本,而不会被其他事务的修改所影响。

  • 写事务: 当一个事务对数据进行写操作时,它会创建一个新的版本。新的版本不会影响正在进行的读事务,直到该写事务提交。
  • 读事务: 读操作可以读取提交前的旧版本数据,以保证读取的一致性,即事务看到的数据是一致的,不会被其他未提交的修改所影响。

三、实现原理

多版本并发控制MVCC)的 实现原理 基于以下几个核心概念和机制,它们共同工作以实现高效的并发控制和事务隔离。


在这里插入图片描述

四、示例解释

假设有一个账户余额数据库,账户的初始余额是100。现有两个事务并发执行:

❤ 事务A:在余额上加50元。
❤ 事务B:查询账户余额。

⭐ 操作顺序:

1、事务A读取余额(100元),并准备增加50元。	
2、事务B同时启动,读取余额,它看到的是100元(因为事务A的操作尚未提交,事务B只会看到旧版本的余额)。
3、事务A提交,将余额更新为150元。
4、事务B继续进行操作,它读取的仍然是余额100元,而不是事务A提交的150元,因为事务B在读取时,事务A的修改还未生效。

在这个过程中,事务B看到的余额是事务开始时的一致性快照(即100元),而不是事务A提交后的150元。这保证了事务B的读操作与事务A的写操作不冲突。

五、MVCC 优点

  • 非阻塞读:读操作不会被写操作阻塞,反之亦然。即使有多个事务同时修改数据,读事务可以无锁地执行。
  • 提高并发性:由于事务可以并发执行,数据库的吞吐量得以提高。
  • 事务隔离:MVCC通过创建多个版本的数据,可以为事务提供更好的隔离性,尤其是读未提交、读已提交和可重复读这几种隔离级别。

六、现实中的实现

许多现代数据库系统,如PostgreSQLMySQLInnoDB引擎,都实现了MVCC。以MySQLInnoDB为例:

  • 每条记录有两个额外的隐藏列,分别存储了 创建该版本的事务ID删除该版本的事务ID 。当一个事务读取记录时,数据库会根据这些ID来判断该事务是否能够看到该记录的版本。
  • 快照读: 事务读取时基于该事务启动时的快照,可以避免读取到其他事务未提交的修改。

七、MVCC 三剑客

MVCC 三剑客是指 MVCC 机制中与事务和并发控制密切相关的 三个核心概念,分别是 ReadViewUndo LogPurge。这三者共同作用,确保多版本并发控制能够高效地管理数据的一致性和并发性。


1. ReadView

ReadView 是在事务读取数据时生成的一个一致性视图,它记录了当前活跃的事务及其事务ID,用于决定哪些数据版本对当前事务可见。

ReadView 的作用:

  • 一致性读ReadView 确保事务读取到的数据是一致的,即使有其他事务正在对数据进行修改,事务只会看到与其一致性视图相关的版本。
  • 事务隔离ReadView 通过记录当前未提交的事务,帮助事务实现“快照隔离”(Snapshot Isolation)或“可重复读”(Repeatable Read)等隔离级别。

ReadView 的工作方式:

  • 当事务第一次执行查询时,系统会生成一个 ReadView,记录当前所有活跃事务的事务ID列表。
  • 根据这些事务ID,决定当前事务读取到的数据版本。事务只能看到在其开始之前已经提交的数据版本,未提交的修改或后续的修改对当前事务不可见。

2. Undo Log

Undo Log 是事务修改数据时生成的日志,它记录了每次修改之前的数据状态,以便在事务回滚时能够撤销这些修改,恢复到原始状态。

Undo Log 的作用:

  • 事务回滚:当事务回滚时,系统利用 Undo Log 将修改的数据恢复到未修改之前的状态。
  • 版本控制:在 MVCC 中,Undo Log 也用于保存旧版本的数据,使得并发事务能够读取已提交的历史数据。

Undo Log 的工作方式:

  • 每当一个事务修改数据时,InnoDB 会生成一个 Undo Log 记录,保存修改前的旧版本数据。
  • 如果事务需要回滚,Undo Log 中的数据可以用来撤销修改,恢复到修改前的状态。
  • Undo Log 还用于构建历史版本数据,允许并发事务读取旧版本。

例如,假设事务A对记录 R 进行修改,将其值从 100 改为 150。在修改时,Undo Log 会保存原始值 100,以便回滚时能够恢复。


3. Purge

PurgeInnoDB 的一种后台清理机制,用于删除不再需要的旧版本数据和 Undo Log 记录,释放存储空间。

Purge 的作用:

  • 回收空间:当某个旧版本的数据不再需要被事务访问时,Purge 会将这些版本数据从存储中删除,以释放磁盘空间。
  • 清理 Undo Log:如果某条记录的 Undo Log 记录不再需要(即所有相关的事务都已提交或回滚),Purge 进程会将这些日志删除。

Purge 的工作方式:

  • InnoDB 定期会有一个后台进程负责清理不再需要的历史版本和 Undo LogPurge 过程保证旧版本的数据不会无限增长,防止存储空间耗尽。
  • Purge 进程会根据事务的活跃情况,清理那些不再被任何事务引用的历史版本。只有当某个旧版本的数据和 Undo Log 对所有事务都不可见时,才会被清理。

4. 三者之间的关系:

  • ReadView 确保事务读取到一致的快照,并通过事务ID列表确定哪些版本对事务可见。
  • Undo Log 保存事务的修改前状态,用于支持回滚操作和历史版本数据的读取。
  • Purge 定期清理不再需要的旧版本和 Undo Log,确保数据库的存储空间得到有效利用。

5. 示例

假设有两个事务A和B同时对一条记录 R 进行操作:


1、事务A:开始并读取记录 R,此时 ReadView 生成,记录了当前系统中的活跃事务状态。

2、事务B:修改记录 R 的值并创建 Undo Log,保存修改前的旧值。事务B未提交时,事务A读取的仍然是旧版本数据。

3、事务B:提交后,新版本的 R 对其他事务可见。如果事务A的 ReadView 是在事务B提交之前生成的,它依然会读取旧版本数据。

4、Purge:在事务A结束后,系统中的其他事务也结束,事务B创建的旧版本不再需要,后台 Purge 进程将清理掉这些旧版本和对应的 Undo Log。


通过 ReadView、Undo Log 和 Purge 的协作,系统实现了多版本并发控制,确保数据读取一致性、事务回滚能力和存储空间的高效利用。

6. 总结

MVCC 三剑客(ReadViewUndo LogPurge)是 MVCC 机制中不可或缺的三个核心组件。它们分别负责确保事务读取一致的快照、提供数据版本的回滚能力、以及清理不再需要的旧版本数据,从而实现高效的并发控制和空间管理。


总结:
MVCC通过创建数据的多个版本,避免了读写冲突,提升了数据库系统的并发性能。其 核心思想 是:读操作读取旧版本数据,写操作创建新版本数据,从而实现非阻塞的并发控制

八、MVCC 整体操作流程

多版本并发控制(MVCC)的整体操作流程通过创建和维护数据的多个版本,确保数据库中多个事务能够并发执行,提供一致性读和事务隔离。下面详细介绍MVCC的整体操作流程,涵盖事务启动、读取、写入、提交和回滚等操作。


操作流程简述
1. 事务启动分配事务ID,准备执行操作
2. 读操作通过 ReadView 生成快照,确保读取数据的一致性
3. 写操作创建新版本而不影响现有版本,保证读写并发
4. 提交操作新版本提交后对其他事务可见
5. 回滚操作撤销事务的修改,恢复旧版本
6. 并发控制通过版本判断实现读写并发,同时使用锁机制处理写写冲突
7. 垃圾回收清理旧版本,释放存储空间

在这里插入图片描述

⭐、readview

多版本并发控制(MVCC)系统中,ReadView 是一个 用于实现一致性读 的概念。它是在事务执行过程中生成的一个快照,用于决定当前事务可以看到哪些数据版本。特别是在 MySQLInnoDB 存储引擎中,ReadView 负责管理事务在读取数据时能看到的数据状态。

1. 作用

当一个事务开始进行查询操作时,InnoDB 会创建一个 ReadView,它记录了当前所有活跃事务的快照状态,并帮助事务决定哪些数据版本是对其可见的,哪些版本应该被忽略。

主要作用是:

  • 确保事务读取的数据是一致的,即使在该事务执行期间有其他事务对数据进行了修改。
  • 提供一致性读(Consistent Read),即事务在读取时看到的数据是该事务开始时的快照,而不会被其他未提交的修改影响。

2. 工作机制

在创建 ReadView 时,InnoDB 记录了系统中当前所有活跃的事务,特别是这些事务的事务IDTransaction ID,trx_id)。接下来,系统通过以下规则来决定哪些数据版本是可见的:

trx_id 列表
ReadView 包含以下几个重要的事务ID相关的信息:

  • m_ids(活跃事务ID列表):所有在创建 ReadView时未提交的事务ID。这些事务对当前事务来说是“活跃的”,其修改的版本数据不可见。
  • min_trx_idm_ids 中最小的事务ID。任何小于这个ID的数据版本都对当前事务可见,因为它们在当前事务开始之前已经提交。
  • max_trx_idReadView 创建时分配的最大事务ID,任何大于或等于这个ID的事务都是在当前事务之后开始的,它们的修改数据对当前事务不可见。

通过这些信息,InnoDB 可以为每个查询提供一个一致的视图,让事务看到的是当前快照中的数据,而不是其他未提交事务的修改。


3. 数据版本的可见性判断规则

在决定一个数据版本是否对当前事务可见时,系统会按照以下步骤来检查该版本的事务IDtrx_id):

  • 如果trx_id < min_trx_id,表示该版本是由比所有活跃事务都早的事务创建的,因此它已经提交,可以被当前事务看到。
  • 如果 trx_id in m_ids,表示该版本的创建事务仍然活跃,尚未提交,因此该版本不可见。
  • 如果 trx_id >= max_trx_id,表示该版本是由在当前事务之后开始的事务创建的,因此不可见。

通过这些规则,ReadView 确保了每个事务只看到在它开始之前已经提交的数据版本,从而实现一致性读。


4. 应用场景

ReadView 通常在以下场景中发挥作用:

  • 可重复读(Repeatable Read)隔离级别 在这个隔离级别下,事务从开始到结束,看到的都是同一个快照。ReadView 是在第一次读取操作时创建的,之后的每次读取操作都基于这个快照,从而保证可重复读。

  • 快照隔离(Snapshot Isolation) 类似于可重复读,事务看到的是它开始时的快照,通过 ReadView 实现。

5. 示例

在这里插入图片描述


6. 总结

ReadViewMVCC 的核心组件之一,用于管理事务的快照状态。 它通过记录当前系统中的活跃事务列表,帮助决定哪些数据版本对当前事务可见,哪些版本不可见。ReadView 确保了事务在并发执行时能够看到一致的数据快照,从而实现了非阻塞的并发控制。



⭐、隐藏字段

在使用多版本并发控制(MVCC)的数据库系统中,隐藏字段 是一些额外的元数据字段,它们在用户的表结构中是不可见的,但对数据库的内部操作至关重要。隐藏字段通常用于存储与多版本控制和事务管理相关的信息,以帮助数据库系统实现高效的并发控制、数据版本管理和事务隔离。以下是这些隐藏字段的详细说明,主要以 MySQLInnoDB 引擎为例。


1. DB_TRX_ID(事务ID)

DB_TRX_ID 是每条记录的事务ID字段,用于记录最后修改该记录的事务ID

  • 作用:当一个事务对某条记录进行修改时,InnoDB 会将该事务的事务IDTransaction ID, trx_id)写入该字段,表示这是由哪个事务最后修改的版本。这个字段对于判断记录的可见性非常重要,因为每个事务只会读取到在其开始之前提交的事务生成的版本。
  • 用途:在读取记录时,数据库根据读取事务的事务ID与该记录的事务ID进行比较,决定该版本是否对当前事务可见。

举例:
假设事务A对记录 R 进行了修改,事务AID是 10,那么 RDB_TRX_ID 字段将被更新为 10。当另一个事务B(事务ID为 15)读取这条记录时,数据库会根据 DB_TRX_ID 判断事务B是否能看到该版本。


2. DB_ROLL_PTR(回滚指针)

DB_ROLL_PTR 是一个回滚指针,用来指向与该记录相关的Undo Log 记录。通过这个字段,数据库可以追溯到该记录的历史版本。

作用: DB_ROLL_PTR 用于指向该记录的 Undo Log 中的日志,Undo Log 保存了记录在被修改之前的状态。因此,通过回滚指针,数据库可以找到记录的旧版本数据,从而在事务回滚或并发读取时获取历史版本。

用途: 这个字段在事务回滚和读取旧版本时非常有用。通过它,数据库可以沿着 Undo Log 追溯到历史版本,以支持 MVCC 的一致性读操作。

举例:
当事务A修改了记录 R 后,InnoDB 会为这次修改生成一条 Undo Log,并更新 RDB_ROLL_PTR 字段,指向这条 Undo Log。如果需要回滚或读取旧版本数据,系统会通过这个指针找到对应的 Undo Log 来获取旧值。


3. DB_ROW_ID(行ID)

DB_ROW_ID 是一个唯一标识每条记录的行ID。在没有主键的表中,InnoDB 会为每条记录自动分配一个行ID,作为记录的唯一标识。

作用: 即使表中没有显式的主键字段,InnoDB 仍然需要一个唯一的标识符来区分每条记录。DB_ROW_ID 是一个自增的数字,用于唯一标识表中的每条记录。

用途: 如果表没有定义主键,InnoDB 会使用 DB_ROW_ID 作为内部的聚簇索引键。虽然用户看不到这个字段,但它在内部用于对表数据进行唯一定位。

举例:
如果用户创建了一张没有主键的表,InnoDB 会自动为每条记录分配一个 DB_ROW_ID,这个值会递增。即使用户没有显式地看到该字段,它在表的内部存储中用于唯一标识每条记录。



隐藏字段的工作机制

InnoDB 引擎中,隐藏字段MVCC 实现至关重要。它们通过提供事务ID回滚指针行ID等信息,帮助系统管理数据的多个版本并实现以下功能:

  • 事务隔离: 通过 DB_TRX_ID 来判断每条记录的版本是否对当前事务可见,从而确保不同事务之间的数据读取不会相互影响。
  • 版本回溯: 通过 DB_ROLL_PTR,数据库能够追溯到记录的历史版本,从而支持并发读操作和事务回滚。
  • 记录唯一性: 通过 DB_ROW_ID,即使表中没有定义主键,InnoDB 仍能唯一标识每条记录。

例子:隐式字段在事务中的作用

假设有两个并发事务A和B:

1、事务A:修改了一条记录 R,将值从 100 改为 150。同时,事务A的事务ID 10 被写入该记录的 DB_TRX_ID 字段,并创建了一个 Undo Log,保存原来的值 100。记录的 DB_ROLL_PTR 更新为指向这个 Undo Log

2、事务B:同时读取记录 R,事务B的事务ID15。由于事务A尚未提交,事务B会通过 DB_TRX_ID 检查该记录的修改是否对其可见。系统发现 DB_TRX_ID 小于事务B的事务ID,因此事务B会读取修改前的版本,即通过 DB_ROLL_PTR 指向的 Undo Log,获取到值 100

3、事务A 提交后DB_TRX_ID 仍然记录事务AID 10,但此时事务A的修改已经提交,后续的事务读取 R 时将直接看到修改后的值 150







总结
隐藏字段MVCC 实现中起着至关重要的作用。它们虽然对用户不可见,但它们存储了关于事务和版本控制的关键信息,帮助数据库系统有效地管理数据版本、提供一致性读、支持事务回滚以及提升并发性能。



http://www.kler.cn/news/327340.html

相关文章:

  • 字体文件压缩
  • 深入 Spring RestTemplate 源码:掌握 HTTP 通信核心技术
  • dockerfile部署springboot项目(构建镜像:ebuy-docker:v1.0)
  • Java高效编程(7):消除过时的对象引用
  • 【计算机网络】详解HTTP请求和响应格式常见请求方法Header报头响应报文状态码URL
  • \?拉普拉斯到底在讲什么\?控制理论\?倒立摆/
  • Linux: network: /proc/net/sockstat 解读
  • 163页制造业变革转型:营销/服务/研发/供应链/制造/质量/财务
  • 车视界系统小程序的设计
  • 数据结构——队列的基本操作
  • 鸿蒙开发(NEXT/API 12)【请求用户授权】手机侧应用开发
  • 在Java中使用GeoTools解析POI数据并存储到PostGIS实战
  • 手机如何五开玩梦幻西游端游?用GameViewer远程手机免费畅玩梦幻西游
  • 【大数据】数据中台怎么样助力企业创新和客户实践
  • C++学习,信号处理
  • 组播基础-1
  • 结构体内存对齐与位段
  • 基于 Qwen2.5-0.5B 微调训练 Ner 命名实体识别任务
  • Java数据结构链表(LinkedList详解)
  • Vue3 Typescript 前端页面5min后无操作自动退出至登录页面
  • Windows上面搭建Flutter Android运行环境
  • cmd下的管理员权限闪退 原理分析
  • 【Rockchip系列】官方函数:drm_buf_alloc
  • 【Kotlin基于selenium实现自动化测试】初识selenium以及搭建项目基本骨架(1)
  • 华为OD机试 - 超级玛丽通过吊桥的走法 - 动态规划(Python/JS/C/C++ 2024 E卷 200分)
  • 数据结构——计数、桶、基数排序
  • 深入探索 PyTorch 在机器学习中的应用
  • 观测云对接 SkyWalking 最佳实践
  • Springboot中yml文件不生效原因分析及解决
  • 【C++篇】启航——初识C++(下篇)