一个欲儿的博客

一个欲儿的博客

MySQL MVCC版本控制中如何实现的可重复读
2025-08-29

工作当中遇到了一个问题,被ld狠狠骂了,问我为什么这个问题都犯错,骂了我半天,我一直问他,他绕过了绕过去没说明白,我想了半天也没理解到ld说的错误到底在哪里,直到ld说让我去看一下小林coding,我真去看了,结果发现小林coding写错了,我靠了,兄弟,要不是因为我赚这窝囊费,我真的不想忍这个气,所以这里纠正小林coding的一些地方,事实上我后面啥也没改,然后我跟他说我看了,已经改了,问题就解决了,这你说扯不扯兄弟

一、知识储备

1. 事务 ID(Transaction ID, trx_id)

每个事务在开始时都会分配一个唯一的事务 ID。

事务 ID 随时间递增,用于区分不同事务对同一行数据的修改版本。

事务 ID 在版本链上标识该事务修改数据的顺序。

2. ReadView

ReadView 是事务在执行一致性读(快照读)时生成的快照。

它记录了在快照生成时系统的事务状态:

m_ids:活跃事务 ID 列表(尚未提交的事务)

min_trx_id:活跃事务中最小的事务 ID

max_trx_id:下一个待分配的事务 ID

creator_trx_id:当前事务 ID(即自己)

核心作用:

定义事务能看到哪些数据版本

保证事务内一致性读取(读自己未提交的修改总是可见)

3. ReadView 与自己事务的关系

小林coding的错误就在这里,这个地方是错的,自己id根本就不会出现在m_ids里面去,而小林coding是出现了的,所以这个地方他跟我扯半天扯不懂,救命

自己事务的 ID 永远不会出现在 m_ids 中

自己修改的数据对自己总是可见(Read Your Own Writes)

m_ids 只记录 其他尚未提交的事务

4. ReadView 与版本可见性

image.png

二、实例

我就不扯那些文绉绉的东西了,直接来实例好吧

假设有如下事务,id分别为 13 14 15 16 17 18,分别修改一个name值为13n,14n,15n,16n,17n,18n

现在执行事务17,这个时候拍一个快照ReadView

假设事务13 14 16已经提交了,15还未提交,18未开始,前期理解可以理解没有18这个事务,方便理解

这个时候的ReadView如下:

m_ids:15

min_trx_id:15

max_trx_id:18

creator_trx_id:17

这个时候会去读name的版本链 由于18 大于等于 max_trx_id 所以不可见 跳过

然后这里就要分两种情况了,那就是17这个事务到底修改name这个数据

1. 事务17修改值为17n

这个时候就会直接返回17n,因为以当前事务为准,管你之前是啥,都改到17n

2. 事务17不修改值,只读取

这个时候就会去读取id为16的版本,由于id为16 属于 [min_trx_id,max_trx_id),但是不在m_ids里面,所以16事务是可见的,并且直接返回16n

那如果没有16这个 事务,那就该读取15,但是15在m_ids属于直接不可见,读不了

接着往下读14,由于14 小于min_trx_id 所以是可见的,直接返回14n

如果14n依然不可见就会返回13n


评论列表
  •   访客  发布于 2025-09-12 09:58:37  回复该评论
    我觉得吧,后面的举例貌似忽略了update对数据加排他锁的情况,如果是17事务先获取了排他锁,那么只有在17事务提交了之后15事务才能继续执行,这样最后的结果就是15了。(update是当前读,不会处理readview的逻辑)

发表评论: