MySQL的MVCC机制

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌

博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+MySQL+Vue等前后端分离项目,可以在左边的分类专栏找到更多项目。《Uniapp项目案例》有几个有uniapp教程,企业实战开发。《微服务实战》专栏是本人的实战经验总结,《Spring家族及微服务系列》专注Spring、SpringMVC、SpringBoot、SpringCloud系列、Nacos等源码解读、热门面试题、架构设计等。除此之外还有不少文章等你来细细品味,更多惊喜等着你哦

🍅uniapp微信小程序🍅面试题软考题免费使用,还可以使用微信支付,扫码加群。由于维护成本问题得不到解决,可能将停止线上维护。

🍅文末获取联系🍅精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟

Java项目案例《100套》
https://blog.csdn.net/qq_57756904/category_12173599.html
uniapp小程序《100套》

https://blog.csdn.net/qq_57756904/category_12173599.html

有需求代码永远写不完,而方法才是破解之道,抖音有实战视频课程,某马某千等培训都是2万左右,甚至广东有本科院校单单一年就得3万4年就12万学费,而且还没有包括吃饭的钱。所以很划算了。另外博客左侧有源码阅读专栏,对于求职有很大帮助,当然对于工作也是有指导意义等。在大城市求职,你面试来回一趟多多少少都在12块左右,而且一般不会一次性就通过,还得面试几家。而如果你对源码以及微服务等有深度认识,这无疑给你的面试添砖加瓦更上一层楼。

最后再送一句:最好是学会了,而不是学废了!!

2

MySQL 的 MVCC (Multi-Version Concurrency Control, 多版本并发控制) 是其核心存储引擎 InnoDB 实现高并发、非阻塞读的关键机制。它允许读操作不阻塞写操作,写操作也不阻塞读操作(在特定隔离级别下),从而极大地提升了数据库的并发性能。

以下是 MySQL InnoDB MVCC 的核心要点和工作原理:

  1. 核心思想:保留数据的历史版本

    • 当一行数据被修改时,InnoDB 不会立即覆盖原始数据,而是将原始数据标记为旧版本,并创建一个新版本。

    • 同时进行的读操作仍然可以访问到修改发生前的旧版本数据(快照)。

    • 数据的多个版本(旧版本)保存在 Undo Log 段中。

  2. 实现基础:隐藏字段

    InnoDB 在每一行记录(聚簇索引的叶子节点)中,除了用户定义的列,还添加了三个隐藏的系统字段:

    • DB_TRX_ID (6 Bytes): 记录最后一次修改 (INSERT 或 UPDATE)该行记录的事务 ID

    • DB_ROLL_PTR (7 Bytes): 指向该行记录上一个版本Undo Log 中位置的指针(回滚指针)。利用这个指针可以构建一条该行记录的版本链

    • DB_ROW_ID (6 Bytes): 隐含的自增行 ID(Row ID)。如果表没有定义主键,InnoDB 会自动生成一个聚簇索引基于此字段。

  3. 关键组件:Undo Log

    • 存储被修改数据的旧版本

    • 当进行 UPDATEDELETE 操作时:

      • UPDATE: 将修改前的行数据(包含所有字段)复制到 Undo Log 中,形成一个旧版本记录。然后更新当前行的数据,并将 DB_TRX_ID 设置为当前事务 ID,DB_ROLL_PTR 指向刚刚写入 Undo Log 的旧版本记录。

      • DELETE: InnoDB 实际上并不立即删除数据,而是将其标记为删除(设置一个删除标志)。同时,将删除前的整行数据复制到 Undo Log 中。真正的物理删除(Purge)由后台线程在确定没有任何事务需要访问这些旧版本数据时才进行。

    • Undo Log 主要用于:

      • 事务回滚 (ROLLBACK):通过 DB_ROLL_PTR 找到旧版本数据并恢复。

      • 实现 MVCC:提供一致性读所需的历史快照。

  4. 可见性判断:Read View

    • 当一个事务(通常是只读事务或开启了 START TRANSACTION WITH CONSISTENT SNAPSHOT)执行普通的 SELECT 查询(快照读)时,InnoDB 会为该事务生成一个 Read View(读视图)。

    • Read View 决定了该事务能看到数据的哪个版本。它包含以下关键信息:

      • trx_ids: 生成 Read View 时,系统内所有活跃(已启动但未提交)的读写事务的事务 ID 列表。

      • low_limit_id: 生成 Read View 时,系统应该分配给下一个事务的 ID 值(即当前最大事务 ID + 1)。

      • up_limit_id: 活跃事务列表 trx_ids最小的事务 ID。

      • creator_trx_id: 创建该 Read View 的事务自身的事务 ID(对于只读事务,该值为 0)。

    • 可见性规则 :对于版本链中的每一行记录(通过 DB_ROLL_PTR 回溯),使用该行的 DB_TRX_ID 和当前事务的 Read View 进行判断:

      1. 如果 DB_TRX_ID < up_limit_id:说明该版本是在生成 Read View 之前 就已提交的事务修改的,可见

      2. 如果 DB_TRX_ID >= low_limit_id:说明该版本是在生成 Read View 之后 才开启的事务修改的(或者就是本事务修改的但未提交),不可见。需要沿着版本链继续查找更旧的版本。

      3. 如果 up_limit_id <= DB_TRX_ID < low_limit_id:说明该版本是由在生成 Read View 时活跃的事务修改的。

        • 如果 DB_TRX_IDtrx_ids 列表中,表示该事务当时活跃(未提交),则该版本不可见,继续找旧版本。

        • 如果 DB_TRX_ID 不在 trx_ids 列表中,表示该事务在生成 Read View 时已提交 ,则该版本可见

      4. 如果 DB_TRX_ID = creator_trx_id:说明该版本是由本事务 自己修改的,可见

    • 事务会沿着版本链(通过 DB_ROLL_PTR)依次应用这些规则,直到找到第一个对其可见的版本。

  5. 与事务隔离级别的关系

    MVCC 主要在 READ COMMITTED (RC)REPEATABLE READ (RR) 隔离级别下发挥核心作用。它们的主要区别在于 Read View 的生成时机

    • READ COMMITTED (RC)

      • 每次执行 SELECT 语句(快照读)时,都会重新生成一个最新的 Read View。

      • 因此,它能读取到最新已提交的数据。解决了脏读,但可能出现不可重复读和幻读。

    • REPEATABLE READ (RR)

      • 在事务中第一次执行 SELECT 语句(快照读)时 生成一个 Read View。在整个事务期间,后续的所有快照读都复用这个第一次生成的 Read View

      • 因此,在同一个事务内,多次读取同一条记录,看到的是同一个历史快照(第一次读时的状态)。解决了脏读和不可重复读。

      • InnoDB 在 RR 级别下还通过 Next-Key Locking(间隙锁)机制来防止幻读(MVCC 的快照读本身不能完全防止幻读,因为新插入的数据可能不在快照中,但当前读会加锁阻止插入)。

  6. 快照读 vs. 当前读

    • 快照读 (Snapshot Read)

      • 普通的 SELECT 语句(不加 FOR UPDATELOCK IN SHARE MODE)。

      • 使用 MVCC 机制,读取历史版本(Read View 决定),不加锁(理论上,可能遇到历史数据被 Purge 清理的情况,但通常不影响一致性)。

      • 目的是提供一致性的非锁定读。

    • 当前读 (Current Read)

      • SELECT ... FOR UPDATE

      • SELECT ... LOCK IN SHARE MODE

      • UPDATE, DELETE, INSERT

      • 读取的是数据的最新提交版本

      • 加锁(记录锁、间隙锁、Next-Key 锁)以保证操作的正确性和防止并发冲突。

      • 目的是处理当前最新的数据状态并进行修改。

  7. Purge 操作

    • 随着事务的提交,不再需要访问的旧版本数据(Undo Log)会变得多余。

    • InnoDB 的后台线程 Purge Thread 会负责清理这些不再被任何 Read View 依赖的旧版本数据和 Undo Log 空间。这个过程称为 Purge。

    • 长事务会阻止 Purge 线程清理它可能需要的旧版本数据,导致 Undo Log 膨胀,这是需要注意的。

总结 MySQL InnoDB MVCC 的优势:

  • 高并发读: 读操作通常不需要加锁,不会被写操作阻塞。

  • 非阻塞写: 写操作通常只需要锁定当前处理的行(或间隙),不会阻塞其他行的读操作(快照读)。

  • 一致性读: 在不同隔离级别(RC/RR)下提供不同强度的一致性视图,避免脏读,解决不可重复读(RR)。

  • 高效回滚: Undo Log 天然支持事务回滚。

需要注意:

  • MVCC 主要在 READ COMMITTEDREPEATABLE READ 隔离级别下有效。READ UNCOMMITTED 总是读最新数据(可能脏读),SERIALIZABLE 会对所有读加锁,不使用 MVCC 的快照读。

  • MVCC 会增加存储开销(Undo Log 存储历史版本)和 CPU 开销(构建和遍历版本链)。

  • 理解 DB_TRX_ID, DB_ROLL_PTR, Undo Log, Read View 以及可见性规则是掌握 MVCC 的关键。

通过 MVCC,MySQL InnoDB 在保证事务隔离性的同时,极大地提高了数据库的并发处理能力,是现代 OLTP 应用高性能的重要基石。

3

相关推荐
一只叫煤球的猫2 小时前
MySQL 8.0 SQL优化黑科技,面试官都不一定知道!
后端·sql·mysql
寒山李白2 小时前
MySQL安装与配置详细讲解
数据库·mysql·配置安装
文牧之3 小时前
PostgreSQL 的扩展pg_freespacemap
运维·数据库·postgresql
deriva3 小时前
某水表量每15分钟一报,然后某天示数清0了,重新报示值了 ,如何写sql 计算每日水量
数据库·sql
Leo.yuan4 小时前
数据库同步是什么意思?数据库架构有哪些?
大数据·数据库·oracle·数据分析·数据库架构
zhangzhangkeji4 小时前
(33)课54--??:3 张表的 join-on 连接举例,多表查询总结。
mysql
Kookoos4 小时前
ABP VNext 与 Neo4j:构建基于图数据库的高效关系查询
数据库·c#·.net·neo4j·abp vnext
云之兕5 小时前
MyBatis 的动态 SQL
数据库·sql·mybatis
gaoliheng0065 小时前
Redis看门狗机制
java·数据库·redis