MVCC介绍

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

MVCC(Multi-Version Concurrency Control) 是一种数据库并发控制技术,核心思想是通过维护数据的多个版本来实现读写操作的无锁并发,从而在高并发场景下提升性能。它广泛用于 MySQL(InnoDB)、PostgreSQL 等数据库,尤其在 READ_COMMITTEDREPEATABLE_READ 隔离级别下解决脏读、不可重复读和幻读问题。


一、为什么需要 MVCC?

传统锁机制(如行锁、表锁)的缺陷:

  1. 读写冲突:读操作会阻塞写操作,写操作也会阻塞读操作,降低并发性能。

  2. 锁管理复杂:需要处理死锁、锁升级等问题。

MVCC 的优势

  • 读操作不阻塞写操作,写操作也不阻塞读操作。

  • 天然支持非阻塞的"快照读"(Snapshot Read),实现事务隔离。


二、MVCC 核心思想

  1. 数据多版本

    同一行数据在不同时间点存在多个版本,每个版本关联一个事务 ID(或时间戳)。

  2. 快照读

    事务读取数据时,基于当前事务的"可见性规则"选择一个合适的数据版本,而非直接读取最新数据。

  3. 版本链

    每个数据行通过隐藏字段(如 DB_TRX_IDDB_ROLL_PTR)链接到旧版本数据,形成版本链。


三、MVCC 实现原理

MySQL InnoDB 为例,详细说明 MVCC 的机制:

1. 关键隐藏字段

InnoDB 每行数据包含两个隐藏字段:

  • DB_TRX_ID:最近修改该行数据的事务 ID。

  • DB_ROLL_PTR:指向 Undo Log 中旧版本数据的指针,形成版本链。

2. Undo Log(回滚日志)
  • 存储数据的历史版本,用于构建版本链。

  • 事务回滚时,通过 Undo Log 恢复数据到旧版本。

3. Read View(读视图)

事务在读取数据时生成一个 Read View ,用于判断数据版本是否可见。

Read View 包含以下关键信息:

  • trx_ids:当前活跃(未提交)的事务 ID 列表。

  • min_trx_idtrx_ids 中的最小事务 ID。

  • max_trx_id:当前系统已分配的最大事务 ID +1。

  • creator_trx_id:创建该 Read View 的事务 ID。

4. 可见性判断规则

事务读取数据时,根据 Read View数据版本的 DB_TRX_ID 判断是否可见:

  1. 如果数据版本的 DB_TRX_ID < min_trx_id:该版本对当前事务可见。

  2. 如果数据版本的 DB_TRX_ID > max_trx_id:该版本对当前事务不可见。

  3. 如果 min_trx_id ≤ DB_TRX_ID < max_trx_id

    • DB_TRX_IDtrx_ids 列表中,说明该版本由未提交的事务修改,不可见。

    • 否则,可见。

  4. 如果 DB_TRX_ID = creator_trx_id:该版本由当前事务自身修改,可见。

5. 不同隔离级别的实现差异
  • READ_COMMITTED:每次读取数据时生成新的 Read View(看到已提交的最新数据)。

  • REPEATABLE_READ:在事务第一次读取数据时生成 Read View,后续复用该视图(保证多次读取结果一致)。


四、MVCC 如何解决并发问题

问题 解决机制
脏读 通过 Read View 过滤未提交事务的修改,只读取已提交的数据版本。
不可重复读 REPEATABLE_READ 下,事务复用同一个 Read View,确保多次读取同一数据版本。
幻读 MySQL 的 REPEATABLE_READ 通过 MVCC + 间隙锁(Gap Lock)共同解决。

五、MVCC 的优缺点

优点
  • 高并发:读写操作互不阻塞。

  • 一致性快照:提供稳定的数据视图,支持事务隔离。

  • 避免锁竞争:减少死锁概率。

缺点
  • 存储开销:需维护多个数据版本,占用额外空间。

  • 历史版本清理:需要定期清理 Undo Log 中的旧版本(通过 Purge 线程)。


六、MVCC 在 PostgreSQL 中的差异

PostgreSQL 的 MVCC 实现与 MySQL 不同:

  • 无 Undo Log:直接通过表的多版本存储实现,每个修改生成新版本,旧版本由 Vacuum 进程清理。

  • 事务 ID 回卷问题:事务 ID 是 32 位,存在循环使用问题,需定期维护。


七、实际案例

场景:事务 A 读取数据,事务 B 修改数据
  1. 事务 A(ID=100)开启,读取某行数据,生成 Read View。

  2. 事务 B(ID=200)修改该行数据并提交,生成新版本(DB_TRX_ID=200)。

  3. 事务 A 再次读取时:

    • READ_COMMITTED :生成新 Read View,看到 DB_TRX_ID=200 的版本。

    • REPEATABLE_READ:复用旧 Read View,仍看到旧版本。


总结

MVCC 通过多版本数据、Read View 和 Undo Log 的协同工作,实现了高效的并发控制。它是现代数据库高并发能力的基石,理解其原理对优化事务设计和排查并发问题至关重要。

相关推荐
yanjiaweiya27 分钟前
云原生-集群管理
java·开发语言·云原生
gadiaola35 分钟前
【JavaSE面试篇】Java集合部分高频八股汇总
java·面试
艾迪的技术之路1 小时前
redisson使用lock导致死锁问题
java·后端·面试
今天背单词了吗9801 小时前
算法学习笔记:8.Bellman-Ford 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·开发语言·后端·算法·最短路径问题
天天摸鱼的java工程师1 小时前
使用 Spring Boot 整合高德地图实现路线规划功能
java·后端
东阳马生架构2 小时前
订单初版—2.生单链路中的技术问题说明文档
java
咖啡啡不加糖2 小时前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南2 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
DKPT2 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式