MySQL RC事务隔离的实现原理:ReadView与Undo Log
MySQL的RC(Read Committed)隔离级别核心在于“每次查询都重新生成ReadView”。本文将深入解析ReadView机制如何利用Undo Log版本链条判断数据可见性,以及这一机制如何导致RC级别下可读到其他已提交事务的修改,却依然存在不可重复读现象。
RC隔离级别的核心机制:ReadView与Undo Log
在RC(读已提交)事务运行期间,只要别的事务修改数据并提交,当前事务即可读到对方修改的数据。这意味着RC级别下,同一事务内多次读取同一记录可能得到不同的值,即存在不可重复读和幻读问题。
其背后的实现基础是ReadView机制,该机制基于undo log版本链条实现。当事务发起查询时,系统会生成一个ReadView对象,用于定义当前时刻的可见性范围。具体规则如下:
- 若读取的是事务自己更新的数据,直接可见。
- 若在生成
ReadView之前,已有事务提交了修改,则该修改可见。 - 若在生成
ReadView时,某个事务已经处于活跃状态(未提交),即使它后续提交了,在本次查询中也不可见。 - 若在生成
ReadView之后才开启的新事务,其修改在当前查询中不可见。
RC与RR(Repeatable Read)的关键区别在于ReadView的生成时机:RC级别下,事务在每次发起查询时都会重新生成一个新的ReadView;而RR级别通常在第一次查询时生成一次,整个事务期间复用。
工作原理演示:从插入到提交的完整过程
为了清晰理解这一机制,我们模拟以下场景:数据库表中有一行原始数据,由事务id=50的事务很久以前插入并提交了。此时,数据库中存在两个活跃事务:事务A(id=60)和事务B(id=70)。
第一步:事务B更新数据并生成版本链
假设现在事务B发起update操作,将这条数据修改为值“b”。此时会发生两件事:
- 数据的最新
trx_id被标记为事务B的id,即70。 - 系统在
undo log中生成一条历史版本记录,保留旧数据及其对应的trx_id=50。
第二步:事务A首次查询(ReadView生效)
此时,事务A发起一次查询操作。系统会为事务A生成一个新的ReadView。
事务A查询发现,当前数据的trx_id=70。根据ReadView的规则:
- 检查
m_ids(活跃事务ID列表),其中包含[60, 70]。 - 因为
70存在于活跃事务列表中,说明该数据是在生成ReadView时已经存在但未提交的事务所修改的。 - 由于事务B尚未提交,事务A无法读到事务B修改的值“b”。
接着,MySQL顺着undo log版本链条往下查找,找到一个原始值,其trx_id为50。因为50小于ReadView的min_trx_id,说明这是在读视图生成前就已提交的旧数据,因此事务A可以查到这个原始值。
第三步:事务B提交后,事务A再次查询
当事务B执行commit操作后,事务B不再被视为活跃事务。如果事务A再次发起查询:
生成新的ReadView:由于是RC级别,事务A会重新生成
ReadView。此时活跃事务列表中仅包含事务A自身(id=60)。因此:min_trx_id设为60。max_trx_id(或m_exclusive_limit)设为71(下一个即将分配的ID)。m_ids列表中只包含[60],事务B的id=70不再出现在列表中。
判断可见性:事务A再次查询时发现数据
trx_id=70。虽然70位于min_trx_id和max_trx_id之间,但因为它不在m_ids活跃列表中,这意味着事务B在生成本次ReadView之前就已经提交了。结果:事务A可以读到事务B修改过的值“b”。
这就是RC隔离级别实现“读到已提交数据”的核心逻辑:通过每次查询刷新ReadView来识别哪些活跃事务已变为已提交状态。
总结
RC隔离级别通过更频繁的ReadView生成,实现了比RR更宽松的一致性要求。它解决了某些场景下的并发读取阻塞问题,但也正因为视图频繁变化,无法保证事务内多次读取结果一致。以上就是关于MySQL RC事务隔离的实现原理的详细内容,更多关于MySQL事务隔离级别对比的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









