news 2026/7/14 5:17:43

MySQL 系统学习 第四阶段:MySQL 高级 第六节:MVCC(Multi-Version Concurrency Control,多版本并发控制)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 系统学习 第四阶段:MySQL 高级 第六节:MVCC(Multi-Version Concurrency Control,多版本并发控制)

前面我们学习:

  • 事务:保证一组操作的一致性
  • 锁:解决多个事务同时修改数据的问题

但是有一个问题:

如果所有查询都加锁,数据库还能高并发吗?

答案:

不能。

所以 InnoDB 引入了:

MVCC

读操作不需要加锁,也能读取一致的数据版本


一、为什么需要 MVCC?

假设:

用户表:

id | name | age 1 | Tom | 20

现在两个事务:


事务A:

查询:

SELECT * FROM user WHERE id=1;

事务B:

修改:

UPDATE user SET age=21 WHERE id=1;

如果没有 MVCC:

事务A读取时:

必须等待事务B完成。

结果:

并发能力下降。


有 MVCC:

事务A:

读取旧版本:

age=20

事务B:

修改新版本:

age=21

两个事务互不影响。


二、MVCC 的核心思想

一句话:

数据库保存数据的多个版本,读取时根据事务规则选择合适版本。

例如:

数据:

版本1: age=20 版本2: age=21 版本3: age=22

不同事务:

看到不同版本。


类似 Git:

commit1 | commit2 | commit3

可以查看不同历史版本。


三、InnoDB 实现 MVCC 依赖什么?

主要依靠三个东西:

1. 隐藏字段

2. Undo Log(回滚日志)

3. Read View(读视图)

⭐⭐⭐⭐⭐


四、隐藏字段

InnoDB 每一行数据实际上有隐藏字段。

例如:

用户表:

CREATE TABLE user( id INT, name VARCHAR(20) );

实际上:

InnoDB 保存类似:

id name 隐藏字段: ---------------- DB_TRX_ID DB_ROLL_PTR

① DB_TRX_ID

事务ID。

表示:

哪个事务修改了这条数据。

例如:

事务100修改 DB_TRX_ID=100

② DB_ROLL_PTR

回滚指针。

指向:

上一个版本的数据。

形成版本链。


五、Undo Log(回滚日志)

Undo Log:

作用:

保存数据修改之前的版本。

例如:

原数据:

age=20

事务A修改:

UPDATE user SET age=21;

数据库保存:

Undo Log:

age=20

现在:

当前数据:

age=21

历史数据:

age=20

形成:

当前版本 | | Undo Log | 旧版本

六、版本链是什么?

例如:

数据不断修改:

第一次:

age=20

事务101:

age=21

事务102:

age=22

最终:

age=22 ↓ age=21 ↓ age=20

这就是:

版本链。


七、Read View(读视图)⭐⭐⭐⭐⭐

这是 MVCC 最核心概念。

Read View:

事务进行普通查询时创建的一份可见性规则。

简单理解:

它决定:

我应该看到哪个版本的数据。


例如:

当前数据:

版本3 | 版本2 | 版本1

事务A:

创建 Read View。

规则:

可能看到:

版本2

而不是最新:

版本3

八、MVCC 如何判断数据是否可见?

InnoDB 会比较:

数据版本中的:

DB_TRX_ID

和:

当前事务的 Read View。


简单理解:

如果:

修改数据的事务已经提交:

可以看到。


如果:

修改数据的事务还没有提交:

不能看到。


九、MVCC 解决什么问题?

主要解决:

1. 读写冲突

例如:

事务A:

读取。

事务B:

修改。

不用互相等待。


2. 提高并发

传统方式:

读 | 加锁 | 等待写

MVCC:

读 | 读取历史版本

十、MVCC 与隔离级别关系

MySQL InnoDB 默认:

REPEATABLE READ

可重复读。

为什么可以做到?

因为:

MVCC。


例如:

事务A:

第一次查询:

余额=1000

事务B:

修改:

余额=500

提交。


事务A:

再次查询:

仍然:

余额=1000

因为:

使用同一个 Read View。


十一、MVCC 如何解决不可重复读?

不可重复读:

原因:

第二次读取看到最新数据。


MVCC:

第一次查询:

创建 Read View:

看到版本1

第二次查询:

继续使用:

版本1

所以:

结果一致。


十二、MVCC 和锁的区别

很多人容易混淆。

MVCC
解决问题读一致性并发修改冲突
方式版本控制阻塞等待
是否阻塞通常不阻塞可能阻塞
主要对象读操作写操作

例如:

普通查询:

SELECT * FROM user;

使用:

MVCC。


修改:

UPDATE user SET age=20;

使用:

锁。


十三、普通 SELECT 和 FOR UPDATE 区别

普通查询:

SELECT * FROM user WHERE id=1;

特点:

  • 不加锁
  • 使用 MVCC
  • 读取快照数据

当前读:

SELECT * FROM user WHERE id=1 FOR UPDATE;

特点:

  • 加锁
  • 读取最新数据
  • 用于修改前查询

例如:

库存扣减:

必须:

SELECT stock FROM product WHERE id=1 FOR UPDATE;

不能使用普通 SELECT。


十四、企业开发中的应用

场景1:订单查询

普通:

SELECT * FROM orders WHERE user_id=100;

使用:

MVCC。

高并发:

没问题。


场景2:库存修改

需要:

SELECT stock FROM product WHERE id=1 FOR UPDATE;

使用:

锁。

保证不会超卖。


十五、本节总结

概念作用
MVCC多版本并发控制
目的提高数据库并发能力
Undo Log保存历史版本
版本链保存数据变化记录
Read View判断版本是否可见
普通SELECT使用MVCC
FOR UPDATE使用锁
RR隔离级别依赖MVCC实现可重复读

🎯 本节核心一句话:

MVCC 通过保存数据历史版本,让读操作不需要加锁也能看到一致的数据,是 InnoDB 高并发能力的核心机制。

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

从零实现C++哈希表:深入理解unordered_map底层原理与性能优化

1. 项目概述:为什么我们需要自己实现一个Unordered_map?如果你写过C,尤其是做过一些性能敏感的项目,那你肯定用过或者至少听说过std::unordered_map。它号称平均O(1)的查找、插入和删除复杂度,是处理海量键值对数据时的…

作者头像 李华
网站建设 2026/7/14 5:15:51

C++错误处理实战:从错误码到异常安全与RAII资源管理

1. 项目概述:从“错误码”到“异常安全”的C工程实践在C的世界里,错误处理是每个开发者都无法绕开的课题。无论是刚入门的新手,还是经验丰富的老手,都曾在“程序崩溃”、“逻辑错误”或“资源泄漏”的泥潭中挣扎过。我见过太多项目…

作者头像 李华
网站建设 2026/7/14 5:12:17

Android小游戏开发实战:从Canvas绘制到游戏循环设计

1. 项目概述:为什么选择Android平台开发小游戏?如果你对移动开发感兴趣,或者想亲手创造一个属于自己的游戏世界,那么从“基于Android平台的小游戏设计与实现”入手,绝对是一个绝佳的选择。我身边很多朋友和同事的“入坑…

作者头像 李华
网站建设 2026/7/14 5:07:43

类与对象:面试官让我用机器人传感器解释封装,我讲了五分钟

上篇聊了static的四种用法,今天进入面向对象的世界。 类与对象,是C++最核心的特性,没有之一。面试的时候,几乎每一轮都会涉及到。 讲个真实的面试场景。 去年面试一个应届生,简历上写着"熟悉面向对象编程"。我问:"什么是类?什么是对象?" 他说:…

作者头像 李华
网站建设 2026/7/14 5:06:11

01 Java 程序员为什么要聊 AIGC?现在面试到底卷成什么样了

摘要:本文从Java后端工程师的视角,深入浅出地解释了AIGC和RAG的核心概念,通过生动的比喻让读者快速理解这些技术。文章分析了为什么AIGC/RAG成为Java面试新热点,并提供了从入门到进阶的面试准备路线图,最后给出了面试官…

作者头像 李华