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

MySQL 的多版本并发控制

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

1. 什么是 MVCC?

MVCC(Multi-Version Concurrency Control,多版本并发控制) 是 MySQL InnoDB 引擎的一种并发控制机制,通过保存数据的多个版本,允许不同事务读取不同的数据版本,从而减少锁冲突,提高并发性能

2. MVCC 主要用于哪种隔离级别?

  • 支持 REPEATABLE READ(可重复读)和 READ COMMITTED(读已提交)
  • 不适用于 READ UNCOMMITTED(读未提交)和 SERIALIZABLE(可串行化)
    • READ UNCOMMITTED:直接读最新数据,不需要 MVCC。
    • SERIALIZABLE:使用锁控制并发,也不需要 MVCC。

3. MVCC 的核心机制

MVCC 主要依赖 undo log(回滚日志)+ Read View(读视图) 实现多版本数据管理

(1)数据版本与 undo log

  • 当事务修改数据时,不会直接覆盖旧数据,而是生成新版本,并将旧数据存入 undo log
  • 事务读取数据时,会根据 Read View 规则,从 undo log 获取符合可见性的旧版本
数据版本示例
idnametrx_id(修改它的事务)undo log 旧值
1“Tom”50“Tom_old”(trx_id=48)
2“Alice”51“Alice_old”(trx_id=49)

(2)Read View(读取视图)

Read View 是如何工作的?

每个事务第一次执行 SELECT 查询时,会生成一个 Read View,用来确定哪些事务的更改对当前事务可见,哪些事务的更改不可见。

Read View 主要包含以下信息:

  1. m_ids(未提交事务 ID 集合)

    • 当前正在执行的所有未提交事务的 trx_id
    • 如果一行数据的 trx_idm_ids 里,表示该事务还未提交,这条数据对当前事务不可见。
  2. low_limit_id(最小未提交事务 ID)

    • 所有 m_ids 事务中的最小 trx_id
    • 小于 low_limit_idtrx_id,代表已经提交,对当前事务可见
  3. up_limit_id(当前最大事务 ID)

    • 所有新开启事务的 trx_id 一定大于 up_limit_id
示例:Read View 过滤可见数据

假设有如下数据:

idnametrx_id
1“Tom”48
2“Alice”49
3“Bob”50(未提交)

如果事务 T1 生成 Read View:

  • m_ids = {50}(事务 50 还未提交)
  • low_limit_id = 50
  • up_limit_id = 52(当前最大 trx_id

那么,事务 T1 读取时:

  • trx_id = 48、49 的数据可见(因为 trx_id < low_limit_id)。
  • trx_id = 50 的数据不可见(因为 trx_id ∈ m_ids)。
  • 如果 Bobtrx_id = 50)修改了数据,T1 仍然读取 undo logBob 修改前的数据

4. MVCC 解决了哪些并发问题?

✅ 解决了“不可重复读”

不可重复读(Non-Repeatable Read):

同一事务内,两次 SELECT 结果不一致,因为另一事务 UPDATE 了数据并提交。

🔹 MVCC 解决方案

  • REPEATABLE READ 级别下,每个事务的 Read ViewSELECT 第一次执行时创建,之后查询始终基于这个 Read View,因此 不会看到其他事务 UPDATE 过的数据

🔹 示例

-- 事务 T1
START TRANSACTION;
SELECT name FROM employees WHERE id = 1;  -- 读取 "Tom"
-- 事务 T2
UPDATE employees SET name = "Jack" WHERE id = 1;
COMMIT;
-- 事务 T1
SELECT name FROM employees WHERE id = 1;  -- 仍然读取 "Tom"

T1 读取的始终是事务开始时的数据版本,不会看到 T2 提交的新数据,避免了“不可重复读”。


❌ MVCC 无法解决幻读

幻读(Phantom Read):

同一事务内,两次 SELECT,第二次查询时看到新 INSERT 的数据。

🔹 MVCC 不能防止 INSERT 造成的幻读

  • Read View 只能隐藏已修改的数据的新版本,但无法屏蔽新增数据
  • 解决方案:使用锁机制(Next-Key Lock)防止 INSERT

🔹 示例

-- 事务 T1
START TRANSACTION;
SELECT * FROM employees WHERE salary > 5000;  -- 读出 3 条数据

-- 事务 T2
INSERT INTO employees (id, name, salary) VALUES (100, 'Alice', 6000);
COMMIT;

-- 事务 T1
SELECT * FROM employees WHERE salary > 5000;  -- 读出 4 条数据(幻读!)

🔹 解决方案

SELECT * FROM employees WHERE salary > 5000 FOR UPDATE;

FOR UPDATE 触发 Gap Lock,防止 T2 插入新数据,从而避免幻读!


5. 总结

机制作用依赖的关键技术适用的隔离级别
MVCC让不同事务读取各自可见的数据版本,减少锁竞争undo log + Read ViewREAD COMMITTEDREPEATABLE READ
Read View确定哪些数据版本对当前事务可见trx_id 事务 ID 过滤数据READ COMMITTEDREPEATABLE READ
undo log存储旧数据版本,支持事务回溯事务修改时记录旧值READ COMMITTEDREPEATABLE READ
Next-Key Lock防止 INSERT 造成幻读行锁 + 间隙锁(Gap Lock)REPEATABLE READ(仅 FOR UPDATE / SERIALIZABLE 生效)

🚀 重点总结

  1. MVCC 依赖 undo log + Read View,让事务读取自己的数据版本,减少锁冲突,提高并发性能。
  2. MVCC 只能解决“不可重复读”问题,但无法解决“幻读”,INSERT 造成的幻读必须用锁来解决。
  3. REPEATABLE READ 下的 Read View 保证了事务期间数据一致性,但新插入的数据仍然可见。
  4. SELECT ... FOR UPDATE 触发 Next-Key Lock,防止 INSERT,避免幻读。

这就是 MySQL 的 MVCC 机制,让事务高效并发执行,同时避免大部分锁竞争! 🚀🔥


http://www.kler.cn/a/599026.html

相关文章:

  • 【IntelliJ IDEA快速绑定Maven配置指南】
  • 奇安信2面面试题。。。
  • 基于Python的智慧金融风控系统的设计与实现
  • Spring MVC 执行流程:一个请求在 Spring MVC 中是如何执行的?
  • qt实现一个简单http服务器和客户端
  • 豪越科技消防一体化:数字中国智慧应急的关键支撑
  • Vue3自定义指令实现前端权限控制 - 按钮权限
  • 全球新闻系统发布 -- 项目启动环节
  • 固定翼无人机姿态和自稳模式
  • 区块链技术
  • [笔记] TinyWebServer编译及demo运行过程
  • React-Router路由跳转、传参、抽象封装以及嵌套路由
  • Redisson 分布式锁原理
  • webgl入门实例-06绘制多个大小不同点-深入理解buffer02
  • 【博客节选】再谈Unity 的 root motion
  • Mybatis注解的基础操作——02
  • WPF 样式(Style)和模板(Template)
  • 机器学习课堂4线性回归模型+特征缩放
  • 05STM32定时器-01定时器概述
  • 医学领域的deepseek:Med-R1,用强化学习开启医学视觉语言模型推理