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 与版本可见性

二、实例
我就不扯那些文绉绉的东西了,直接来实例好吧
假设有如下事务,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
发表评论: