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

MySQL 专题(四):MVCC(多版本并发控制)原理深度解析

MySQL 专题(四):MVCC(多版本并发控制)原理深度解析

在这里插入图片描述

在上一篇文章中,我们提到 事务隔离级别 可以解决脏读、不可重复读和幻读问题。那么问题来了:

👉 在高并发场景下,如果每个查询都用锁来保证一致性,性能会不会大幅下降?

答案是:会!

因此 InnoDB 引入了一种更高效的机制 —— MVCC(Multi-Version Concurrency Control,多版本并发控制),它通过“数据多版本快照”来减少加锁,从而在 读多写少 的场景下实现高性能。


一、MVCC 的核心思想

MVCC 的目标是:

  • 读操作几乎不用加锁,就能读到符合隔离级别的数据。
  • 写操作尽量不阻塞读操作。

实现方式:

  • InnoDB 在每一行数据后面都隐藏存了两个额外字段:

    1. trx_id(事务 ID):最近一次修改该行的事务 ID。
    2. roll_pointer(回滚指针):指向 Undo Log(回滚日志)的地址,可以通过它找到历史版本数据。

👉 这样,InnoDB 就能通过回滚日志来“拼凑”出事务开始时的数据快照。


二、Undo Log 与数据快照

举个例子:

  1. user 里有一行数据:

    id = 1, name = 'Tom'
    
  2. 事务 A 修改:

    UPDATE user SET name='Jerry' WHERE id=1;
    
    • InnoDB 会先写 Undo Log:保存 name='Tom' 的旧版本。
    • 然后把数据改成 'Jerry',并记录新的事务 ID。
  3. 事务 B 此时如果需要“读已提交”,就会根据 Undo Log 还原 'Tom'

👉 Undo Log 就像“时光机”,帮助我们看到过去的数据版本。


三、ReadView(读视图)

MVCC 的关键是 ReadView,它决定了事务在某个时刻能看到哪些数据。

当事务执行 SELECT 时,会生成一个 ReadView,其中包含:

  • m_ids:当时活跃事务的 ID 列表。
  • min_trx_id:最小的活跃事务 ID。
  • max_trx_id:下一个将被分配的事务 ID(即最大事务 ID + 1)。
  • creator_trx_id:生成这个 ReadView 的事务 ID。

可见性规则

当读取一行记录时,根据行的 trx_id 与 ReadView 的事务 ID 范围比较:

  1. 如果 trx_id < min_trx_id → 已提交,数据可见。
  2. 如果 trx_id >= max_trx_id → 未来事务,数据不可见。
  3. 如果 trx_idm_ids 里面 → 事务还没提交,不可见。
  4. 否则 → 可见。

👉 通过这个机制,不同事务在同一时刻看到的数据版本可能不一样,这就是“多版本”。


四、不同隔离级别下的 MVCC

1. 读已提交(RC)

  • 每次执行 SELECT,都会生成一个新的 ReadView
  • 事务 A 可能两次读取到不同结果。

2. 可重复读(RR)

  • 在事务开始时生成 ReadView,整个事务期间保持不变。
  • 事务 A 无论执行多少次 SELECT,都能看到一致的数据。

👉 这就是为什么 MySQL 默认使用 RR,同时还能避免“不可重复读”。

3. 串行化(Serializable)

  • 完全依赖锁,不使用 MVCC。

五、MVCC 与幻读

很多同学会问:

MVCC 能不能解决幻读?

答案是:不能完全解决

  • MVCC 保证了“可重复读”,但不能阻止其他事务插入新行(幻影数据)。
  • 为了解决幻读,InnoDB 在 RR 隔离级别 下,还引入了 间隙锁(Gap Lock)临键锁(Next-Key Lock)

六、MVCC 实际应用

  1. 避免长事务

    • 长事务会导致 Undo Log 不断增长,因为历史版本不能被清理。
    • 建议:大事务拆分成小事务,避免长时间持有 ReadView。
  2. 合适的隔离级别

    • OLTP 系统(高并发业务系统):用 RC 提高性能。
    • 对一致性要求极高的场景(比如金融交易):用 RRSerializable
  3. 理解快照读与当前读

    • 快照读(普通 SELECT):走 MVCC,不加锁。
    • 当前读(SELECT … FOR UPDATE / LOCK IN SHARE MODE):走锁机制,保证读到最新数据。

七、总结

  1. MVCC 的核心 = Undo Log + ReadView。
  2. 快照读 依赖 MVCC,可以高并发下无锁读取。
  3. 可重复读(RR) 的实现依赖固定的 ReadView。
  4. 幻读问题 仍需 间隙锁 来解决。

👉 一句话总结:
MVCC 让 MySQL 在“读多写少”的场景中,既能保证一致性,又能兼顾高性能,是 InnoDB 的灵魂设计之一。


http://www.dtcms.com/a/389304.html

相关文章:

  • 【开发者导航】在终端中运行任意图形应用:term.everything
  • [Python]pytest是什么?执行逻辑是什么?为什么要用它测试?
  • Nginx set指令不能使用在http块里,可以使用map指令
  • LeetCode 1759.统计同质子字符串的数目
  • 揭秘Linux文件管理与I/O重定向核心
  • 【PyTorch】DGL 报错FileNotFoundError: Cannot find DGL C++ graphbolt library
  • Autoware不同版本之间的区别
  • 多轮对话-上下文管理
  • 在阿里云私网服务器(无公网IP)上安装 Docker 环境的完整指南
  • opencv DNN模块及利用实现风格迁移
  • 多层感知机:从感知机到深度神经网络的演进
  • centos7 docker compose 安装redis
  • ⸢ 肆-Ⅱ⸥ ⤳ 风险发现体系的演进(下):实践与演进
  • 18兆欧超纯水抛光树脂
  • 第三篇:C++的进化之旅:从C with Class到C++20
  • 机器视觉的手机FPC丝印应用
  • 在Windows上使用Claude Code并集成到PyCharm IDE的完整指南
  • MoPKL与SPAR的思考
  • Ubuntu 启动分配不到 ip 地址问题
  • iOS 推送证书配置 - p12
  • Qt QVPieModelMapper详解
  • 【MySQL数据库管理问答题】第1章 MySQL 简介
  • 铁头山羊视stm32-HAL库
  • iOS 26 帧率检测实战攻略 如何监控FPS、GPU渲染、Core Anima
  • AWS Lightsail vs 阿里云轻量:企业上云服务器选型深度对比
  • stm32中的位带操作的使用意义
  • Qt QStackedBarSeries详解
  • WebSocket Secure(WSS)在Django项目中的使用
  • RocketMQ 部署;与Golang服务交互
  • 南京某高校校园外卖点餐系统_django