news 2026/4/18 12:37:05

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 的 MVCC(多版本并发控制)详解

MVCC(Multi-Version Concurrency Control,多版本并发控制)是 MySQL InnoDB 存储引擎实现事务隔离级别的核心机制,其核心目标是在不加锁(或减少加锁)的情况下,实现读写并发,同时保证事务的隔离性,避免脏读、不可重复读等问题,大幅提升数据库的并发性能。

一、MVCC 的核心思想

MVCC 为每行数据维护多个版本(快照),不同事务在访问同一行数据时,会根据自身的 “视图” 看到不同版本的数据:

  • 读操作(SELECT):无需加锁,直接读取符合事务版本的快照,避免与写操作互斥;
  • 写操作(INSERT/UPDATE/DELETE):不修改原数据,而是创建数据的新版本,旧版本保留(由 undo log 维护),供其他事务读取。

简单来说:写操作创建新版本,读操作读取历史版本,读写互不阻塞。

二、MVCC 的核心依赖组件

InnoDB 实现 MVCC 依赖以下关键数据结构和日志,缺一不可:

2.1 行记录的隐藏列

InnoDB 为每张表的每行数据默认添加 3 个隐藏列(用户不可见),用于版本管理:

隐藏列作用数据类型
DB_TRX_ID最后一次修改该行数据的事务 ID(插入 / 更新),删除视为 “更新”(标记删除)6 字节
DB_ROLL_PTR回滚指针,指向 undo log 中该记录的历史版本(形成版本链)7 字节
DB_ROW_ID行 ID(聚簇索引的默认主键,仅当表无主键 / 唯一索引时生成)6 字节
2.2 Undo Log(回滚日志)
  • 作用:
    保存数据的历史版本(每次修改行数据时,先将旧版本写入 undo log);
    事务回滚时,通过 undo log 恢复数据;
    为 MVCC 提供历史版本数据。
  • 版本链:每行数据的DB_ROLL_PTR指向 undo log 中该记录的上一个版本,所有版本通过回滚指针串联成版本链(头节点是最新版本)。
  • 类型:
    INSERT_UNDO:记录插入操作的 undo 日志(事务提交后可直接删除,因为插入的行仅当前事务可见);
    UPDATE_UNDO:记录更新 / 删除操作的 undo 日志(需保留至所有依赖该版本的事务结束)。
2.3 Read View(读视图)

Read View 是事务在执行快照读(普通 SELECT)时生成的可见性判断规则,决定了当前事务能看到哪些版本的数据。
Read View 的核心属性

属性含义
m_ids当前活跃(未提交)的事务 ID 列表
min_trx_idm_ids中的最小事务 ID
max_trx_id系统下一个要分配的事务 ID(即当前最大事务 ID+1)
creator_trx_id创建该 Read View 的事务 ID

可见性判断规则
对于版本链中的某行数据版本(记其事务 ID 为trx_id),判断是否对当前事务可见:

  1. 如果 trx_id < min_trx_id:该版本由已提交的事务创建,可见;
  2. 如果 trx_id >= max_trx_id:该版本由未来的事务创建,不可见;
  3. 如果 min_trx_id ≤ trx_id < max_trx_id:
  • 若trx_id在m_ids中(事务未提交),不可见;
  • 若trx_id不在m_ids中(事务已提交),可见;
  1. 特殊:如果trx_id = creator_trx_id(当前事务自己修改的数据),可见。
2.4 事务 ID(Trx ID)
  • InnoDB 为每个事务分配唯一的递增事务 ID;
  • 事务开始时不一定分配 ID,仅当执行写操作(INSERT/UPDATE/DELETE)时才分配;
  • 只读事务(仅 SELECT)可能不分配 ID,进一步提升性能。

三、MVCC 的工作流程(以可重复读为例)

MySQL 默认隔离级别是REPEATABLE READ(可重复读),MVCC 在该级别下的核心行为是:事务在第一次快照读时生成 Read View,后续所有快照读复用该 Read View。
示例:两个事务并发操作同一行数据
假设初始数据:表user有一行数据id=1, name=‘Tom’,其DB_TRX_ID=100(初始事务 ID)。

时间事务 A(读)事务 B(写)
T1开始事务开始事务
T21.执行SELECT * FROM user WHERE id=1;(第一次快照读)2.生成 Read View:m_ids=[200](事务 B 的 ID)、min_trx_id=200、max_trx_id=201、creator_trx_id=199 3.读取行版本trx_id=100 < 200,可见,结果:Tom-
T3-1.执行UPDATE user SET name=‘Jerry’ WHERE id=1; 2.分配事务 ID=200 3.旧版本(trx_id=100)写入 undo log 4.新版本数据:name=‘Jerry’,DB_TRX_ID=200,DB_ROLL_PTR指向旧版本
T41.再次执行SELECT * FROM user WHERE id=1; 2.复用 T2 的 Read View 3.新版本trx_id=200在m_ids中,不可见 4.沿着版本链找旧版本trx_id=100,可见 5.结果仍为Tom(可重复读)-
T5-提交事务 B
T61.第三次执行SELECT * FROM user WHERE id=1; 2.仍复用 T2 的 Read View 3.事务 B 已提交,但m_ids仍为[200](Read View 不更新) 4.结果还是Tom-
T7提交事务 A-
T8新事务 C1.执行SELECT * FROM user WHERE id=1; 2.生成新 Read View:m_ids=[]、min_trx_id=201、max_trx_id=202 3.新版本trx_id=200 < 201,可见,结果:Jerry

关键结论:

  • 事务 A 在整个生命周期内,无论事务 B 是否提交,都只能看到第一次快照读时的版本(可重复读);
  • 新事务 C 在事务 B 提交后,能看到最新版本;
  • 全程无锁,读写互不阻塞。

四、MVCC 在不同隔离级别的表现

MVCC 的行为随隔离级别不同而变化,核心差异在于Read View 的生成时机:

隔离级别Read View 生成时机核心行为解决的问题
READ UNCOMMITTED(读未提交)不生成 Read View,直接读取最新版本能看到未提交事务的修改(脏读)无(几乎不用)
READ COMMITTED(读已提交)每次快照读都生成新的 Read View每次读都能看到已提交的最新版本(不可重复读)脏读
REPEATABLE READ(可重复读)第一次快照读生成 Read View,后续复用事务内多次读结果一致(可重复读)脏读、不可重复读
SERIALIZABLE(串行化)不依赖 MVCC,直接加锁(间隙锁 / 行锁)读写互斥,完全串行所有并发问题(性能差)

五、MVCC 的两种读操作

InnoDB 中读操作分为两类,只有快照读依赖 MVCC:

  1. 快照读(Snapshot Read)
  • 定义:读取数据的历史版本,不加锁,依赖 MVCC;
  • 场景:普通 SELECT(无 FOR UPDATE/LOCK IN SHARE MODE);
  • 特点:读写不阻塞,性能高。
  1. 当前读(Current Read)
  • 定义:读取数据的最新版本,且会加锁(行锁 / 间隙锁),不依赖 MVCC;
  • 场景:
    SELECT … FOR UPDATE(排他锁);
    SELECT … LOCK IN SHARE MODE(共享锁);
    INSERT/UPDATE/DELETE(隐式当前读,先读最新版本再修改);
  • 特点:保证读取的是最新版本,会阻塞其他写操作,或被其他写操作阻塞。

六、MVCC 的优势与局限性

优势

  • 读写并发:读不阻塞写,写不阻塞读(快照读),大幅提升高并发场景性能;
  • 隔离性保证:通过版本链和 Read View,精准控制事务可见性,实现不同隔离级别;
  • 无锁读:快照读无需加锁,避免锁竞争和死锁;
  • 事务回滚高效:通过 undo log 快速回滚,无需重做整个操作。
    局限性
  • 版本链膨胀:大量更新操作会导致 undo log 版本链过长,快照读时需要遍历版本链,性能下降;
  • undo log 清理:InnoDB 需要判断哪些 undo log 版本已无事务依赖,清理不及时会占用磁盘空间;
  • 幻读问题(可重复读下):
    MVCC 解决了 “不可重复读”,但未完全解决 “幻读”(例如:事务 A 第一次读 10 行,事务 B 插入 1 行并提交,事务 A 用当前读(如SELECT … FOR UPDATE)会读到 11 行);
  • InnoDB 通过间隙锁(Next-Key Lock) 补充解决幻读(仅可重复读级别)。

七、MVCC 与锁的关系

MVCC 并非完全替代锁,而是与锁配合工作:

  • 快照读:依赖 MVCC,无锁;
  • 当前读:依赖锁(行锁、间隙锁),保证数据一致性;
  • 写操作之间仍需加锁(如行锁),避免写写冲突;
  • 死锁问题仍可能发生(如两个事务互相持有对方需要的锁)。

八、总结

MVCC 是 InnoDB 实现高性能并发的核心,其本质是通过版本链保存数据历史,通过 Read View 判断版本可见性,让不同事务看到不同版本的数据:

  • 核心组件:隐藏列、undo log、Read View、事务 ID;
  • 核心价值:读写分离,提升并发性能,保证事务隔离性;
  • 关键差异:不同隔离级别的 Read View 生成时机决定了隔离性表现;
  • 适用场景:快照读(普通 SELECT),当前读仍需锁配合。

理解 MVCC 是掌握 InnoDB 事务、隔离级别、锁机制的关键,也是优化 MySQL 高并发性能的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:19:43

评估指标查准率和召回率

准确率precision 评估预测的准不准(主要看预测结果) 召回率Recall 评估预测的全不全(主要看金标准) 借用一个例子,在上网搜索文献时,搜到10条结果,其中有5条是相关文献,另外5条是无关文献. 这样,查准率 5 / 10 50% 后来发现整个网上只有这5条相关文献, 则查全率 5 / 5 100%…

作者头像 李华
网站建设 2026/4/18 3:43:59

利用sklearn进行pca降维

from sklearn.decomposition import PCA import numpy as np # 主成分分析PCA def pca():"""主成分分析进行降维"""# 信息保留90%pca PCA(n_components0.9)data pca.fit_transform([[2,8,4,5],[6,3,0,8],[5,4,9,1]])print("")print(…

作者头像 李华
网站建设 2026/4/17 13:26:25

真心建议大专生去试试网络安全,实习期8k!

前言 专科生毕业&#xff0c;找工作难上加难&#xff1f;别急&#xff0c;我来给你指条明路——网络安全行业&#xff01; 在这个学历至上的时代&#xff0c;专科生似乎总是被边缘化。找到工作了&#xff0c;工资低&#xff0c;工作累&#xff0c;难道我们的生活就只能这样了…

作者头像 李华
网站建设 2026/4/18 5:20:34

0基础如何转行学习网络安全?怎么开始?

前言 最近看到很多小伙伴问我关于网络安全转行的问题&#xff0c;今天做了一些总结&#xff0c;其中最多的是&#xff0c;觉得目前的工作不稳定、没前途、工资低又事多&#xff0c;还有一些就是目前工作稳定但还是想多学一门技术傍身的。总的来说&#xff0c;大家主要的问题是…

作者头像 李华
网站建设 2026/4/17 21:11:15

2025年实测!6款降AI率和查ai率工具汇总!

在论文、报告、内容创作越来越严格的时代&#xff0c;查AI率、检测AI率、降AI率 已经成为学生、写作者、博主的日常需求。很多同学因为 AI率过高被导师指出“AI痕迹太重”&#xff0c;甚至退回重写。本文今天一次性告诉你&#xff1a; 检测AI率应该注意什么 免费查AI率的网站有…

作者头像 李华