首页 虚拟现实

MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别

分类:虚拟现实
字数: (6644)
阅读: (1225)
内容摘要:MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别,

MySQL 的 MVCC(Multi-Version Concurrency Control,多版本并发控制)机制是实现事务隔离的关键技术。通过 ReadView 与 Undolog 版本链,MVCC 能够让不同的事务在同一时刻读取到不同的数据版本,从而避免脏读、不可重复读等并发问题。本文将深入探讨 MySQL 在 Read Committed(RC,读提交)和 Repeatable Read(RR,可重复读)这两种隔离级别下,如何利用 MVCC 实现数据一致性。

ReadView:一致性读的“快照”

ReadView 是 MySQL MVCC 中至关重要的概念,它本质上是某个事务在执行查询时,系统为它生成的一个“快照”,用于判断哪些版本的数据对该事务可见。ReadView 中主要包含以下几个关键属性:

  • creator_trx_id: 创建这个 ReadView 的事务 ID。
  • trx_ids: 当前系统中“活跃”的,未提交的事务 ID 列表。
  • low_limit_id: 系统中已分配的最大的事务 ID + 1,也就是下一个要分配的事务 ID。
  • up_limit_id: trx_ids 列表中最小的事务 ID。只有小于 up_limit_id 的事务 ID 修改的数据,才有可能被当前事务读取到。

理解了 ReadView 的作用,就能明白 MySQL 如何控制不同事务对数据的可见性。

MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别

Undolog版本链:数据的历史记录

当一条数据被修改时,MySQL 会将旧版本的数据保存在 Undolog 中,并使用 trx_id 将各个版本的数据串联成一个版本链。这样,即使数据被修改,我们仍然可以通过 Undolog 找到历史版本的数据。

为了方便理解,我们假设有一条记录 id = 1, name = '张三',其初始 trx_id = 10

MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别
  1. 事务 ID 为 20 的事务将 name 修改为 '李四',MySQL 会将 name = '张三', trx_id = 10 的数据写入 Undolog,并将最新的 name = '李四', trx_id = 20 数据指向 Undolog 中的旧版本。
  2. 事务 ID 为 30 的事务又将 name 修改为 '王五',MySQL 同样会将 name = '李四', trx_id = 20 写入 Undolog,并将最新的 name = '王五', trx_id = 30 数据指向 Undolog 中 trx_id = 20 的旧版本。

这样就形成了一条版本链:name = '王五', trx_id = 30 -> name = '李四', trx_id = 20 -> name = '张三', trx_id = 10

RC隔离级别下的MVCC原理

在 RC 隔离级别下,每个事务每次执行查询时,都会创建一个新的 ReadView。这就意味着,如果在同一个事务中,两次查询之间有其他事务提交了修改,那么第二次查询将会读取到最新的数据,从而出现不可重复读的现象。

MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别

举例说明:

  1. 事务 A 开始,trx_id = 100
  2. 事务 A 执行 SELECT * FROM user WHERE id = 1;,创建 ReadView,假设此时 trx_ids = [100], low_limit_id = 101, up_limit_id = 100(因为只有事务A)。 此时,如果 id = 1 的记录的 trx_id 小于 up_limit_id (比如是 80), 则事务 A 可以读取到这个版本的数据。
  3. 事务 B 开始,trx_id = 101,修改了 id = 1 的记录,将 name'张三' 改为 '李四',并提交事务。此时 id = 1 的记录的 trx_id 变成了 101,旧版本 张三 被写入 Undolog。
  4. 事务 A 再次执行 SELECT * FROM user WHERE id = 1;,重新创建 ReadView,此时 trx_ids = [100], low_limit_id = 102, up_limit_id = 100。 此时,最新的 id = 1 记录的 trx_id101,大于 up_limit_id,所以事务A不能直接读取到最新版本。 此时,MySQL 会沿着 Undolog 版本链,找到 trx_id < up_limit_id 的版本。因为找不到,最终会读取到 trx_id = 80 的版本 (最初的版本)。

结论: 在RC隔离级别下,由于每次查询都生成新的ReadView,因此允许读取到其他事务提交的修改,解决了脏读问题,但也带来了不可重复读的问题。

MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别

RR隔离级别下的MVCC原理

在 RR 隔离级别下,每个事务第一次执行查询时,会创建一个 ReadView,并且在整个事务执行期间都使用这个 ReadView。这意味着,无论其他事务如何修改数据并提交,当前事务只能读取到在创建 ReadView 时的那一个“快照”。这样就保证了可重复读。

举例说明:

  1. 事务 A 开始,trx_id = 200
  2. 事务 A 执行 SELECT * FROM user WHERE id = 1;,创建 ReadView,假设此时 trx_ids = [200], low_limit_id = 201, up_limit_id = 200。 此时,如果 id = 1 的记录的 trx_id 小于 up_limit_id (比如是 180), 则事务 A 可以读取到这个版本的数据。
  3. 事务 B 开始,trx_id = 201,修改了 id = 1 的记录,将 name'张三' 改为 '李四',并提交事务。此时 id = 1 的记录的 trx_id 变成了 201,旧版本 张三 被写入 Undolog。
  4. 事务 A 再次执行 SELECT * FROM user WHERE id = 1;,仍然使用第一次查询时创建的 ReadView(trx_ids = [200], low_limit_id = 201, up_limit_id = 200)。此时,最新的 id = 1 记录的 trx_id201,大于 up_limit_id,所以事务A不能直接读取到最新版本。 此时,MySQL 会沿着 Undolog 版本链,找到 trx_id < up_limit_id 的版本。因为找不到,最终会读取到 trx_id = 180 的版本 (最初的版本)。

注意: 在 RR 隔离级别下,如果事务 A 随后执行了 UPDATE 语句,并且 WHERE 条件正好命中了被事务 B 修改过的记录,那么事务 A 会先去读取事务 B 修改后的最新值,然后再进行修改,这就避免了幻读的发生。这种机制被称为“当前读”,通过加锁来保证数据的一致性。

结论: 在 RR 隔离级别下,由于事务期间只使用一个 ReadView,因此可以避免不可重复读的问题,保证了可重复读。

实战经验与避坑指南

  • 合理选择隔离级别: 根据业务需求选择合适的隔离级别。如果对数据一致性要求不高,可以选择 RC 隔离级别,以提高并发性能。如果对数据一致性要求较高,则应选择 RR 隔离级别。
  • 关注长事务: 长事务会占用大量的锁资源,并导致 Undolog 膨胀,影响数据库性能。应尽量避免长事务,将大事务拆分成小事务。
  • 索引优化: 优化 SQL 语句,避免全表扫描,可以有效减少锁冲突,提高并发性能。可以考虑使用诸如 B+ 树索引,或者全文索引(针对特定的文本搜索场景)等技术。
  • 监控数据库状态: 监控数据库的锁等待、慢查询等指标,及时发现并解决性能问题。
  • 考虑使用分布式事务: 如果业务涉及多个数据库或服务,可以考虑使用分布式事务,例如 Seata,来保证数据的一致性。结合诸如 Dubbo 等 RPC 框架,可以构建复杂的微服务架构。

理解 MySQL MVCC 的原理,可以帮助我们更好地选择隔离级别、优化 SQL 语句,从而提高数据库的并发性能和数据一致性。

MySQL MVCC深度剖析:ReadView与Undolog版本链揭秘RC和RR隔离级别

转载请注明出处: 键盘上的咸鱼

本文的链接地址: http://m.acea2.store/article/42466.html

本文最后 发布于2026-04-18 04:10:57,已经过了9天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 芝麻糊 2 天前
    文章深入浅出,非常适合想深入了解 MySQL MVCC 的同学阅读。点赞!
  • 键盘侠本侠 6 天前
    受益匪浅!以前对 MVCC 的理解比较模糊,看了这篇文章之后清晰了很多,感谢分享。
  • 风一样的男子 1 天前
    受益匪浅!以前对 MVCC 的理解比较模糊,看了这篇文章之后清晰了很多,感谢分享。
  • 山西刀削面 6 天前
    实战避坑指南很实用,长事务确实是个大坑,以前就因为一个长事务导致数据库性能急剧下降。
  • 太阳当空照 1 天前
    文章深入浅出,非常适合想深入了解 MySQL MVCC 的同学阅读。点赞!