RC和RR隔离级别下MVCC的差异,以及MVCC如何解决不可重复读

张开发
2026/4/24 1:02:25 15 分钟阅读

分享文章

RC和RR隔离级别下MVCC的差异,以及MVCC如何解决不可重复读
一、基础概念在讲差异之前先简单说下3个关键概念「隔离级别」MySQL为了防止并发操作时数据错乱给事务定的“规矩”RC和RR是最常用的两个RR是MySQL默认的「MVCC」简单说就是MySQL的一种“多版本数据管理方式”给数据存了多个历史版本读数据时不用加锁还能保证数据一致性核心是“读不阻塞写写不阻塞读”「不可重复读」同一个事务里两次读同一条数据结果不一样比如第一次读是100第二次读变成80这就是不可重复读后面会详细说场景。补充一句MVCC只在RC和RR这两个隔离级别下生效其他两个隔离级别用不到。二、重点RC和RR隔离级别下MVCC的核心差异这是最核心的部分。其实差异就一个关键点记牢这个就够了——MVCC生成“数据快照”的时机不一样。先解释下“数据快照”就是你读数据的时候MySQL给你拍了一张数据的“照片”你读的就是这张照片里的数据而不是实时的最新数据这样就能避免读和写互相阻塞。1. RC读已提交下的MVCC每次读都拍一张新快照RC隔离级别下MVCC的规则很简单同一个事务里每执行一次查询SELECT就生成一张新的“数据快照”。举个简单场景新手能看懂① 事务A开启第一次查询用户余额得到100元此时MVCC拍了一张快照快照里余额是100② 事务B开启把这个用户的余额改成80元并且提交了事务③ 事务A再次查询这个用户的余额此时MVCC又拍了一张新快照能看到事务B提交的修改所以第二次读到的是80元。核心特点RC下的MVCC每次读都更“新”能看到其他事务已经提交的修改但也会导致「不可重复读」同一个事务两次读结果不一样。2. RR可重复读下的MVCC只在第一次读时拍一张快照全程复用RR是MySQL默认的隔离级别这里的MVCC规则和RC完全不同同一个事务里只有第一次执行查询SELECT时才生成一张“数据快照”后续所有的查询都复用这张快照。还是用上面的场景换RR隔离级别① 事务A开启第一次查询用户余额得到100元MVCC拍快照余额100这张快照会一直用② 事务B开启把余额改成80元提交事务③ 事务A再次查询还是用第一次的快照所以读到的还是100元看不到事务B的修改。核心特点RR下的MVCC快照只拍一次全程复用同一个事务里多次读同一条数据结果始终一样这就解决了「不可重复读」问题。总结差异隔离级别MVCC快照生成时机是否会出现不可重复读RC读已提交每次查询都生成新快照会两次读结果可能不一样RR可重复读第一次查询生成快照全程复用不会两次读结果一致一句话RC多快照RR单快照这就是两者最核心的差异。三、MVCC机制是如何解决不可重复读问题的搞懂了上面的差异这个问题就很简单了——MVCC解决不可重复读核心就是靠「RR隔离级别下的单快照机制」再配合“数据版本链”不用懂底层懂逻辑就行。还是用大白话场景一步步讲清楚新手能直接看懂第一步先明白“不可重复读”到底是什么问题前面简单提过再详细说下场景更容易理解假设没有MVCC在RC隔离级别下事务A第一次读用户余额是100此时事务B修改余额为80并提交事务A再读就是80——同一个事务两次读同一条数据结果不一样这就是不可重复读。这种问题在实际开发中很麻烦比如对账的时候两次读的数据不一样就会出错。而MVCC的出现就是为了解决这个问题准确说是RR下的MVCC解决。第二步MVCC解决不可重复读的核心逻辑MVCC解决问题的思路很简单给数据存“历史版本”让同一个事务全程读同一个版本的数据不管其他事务怎么修改都不影响它。具体流程结合RR隔离级别新手能看懂事务A开启第一次执行查询比如查用户余额MVCC会生成一张“数据快照”这张快照里记录了当前数据的版本比如余额100对应一个版本号MVCC会给数据维护一个“版本链”每次其他事务修改数据比如事务B把余额改成80不会覆盖原来的数据而是生成一个新的版本余额80新的版本号旧版本会保留事务A后续再查询时不会去读最新的版本而是一直复用第一次生成的快照去版本链里找快照对应的那个旧版本余额100哪怕其他事务修改并提交了数据事务A读到的还是自己快照里的旧版本所以两次读的结果完全一样也就解决了不可重复读。补充为什么RC下的MVCC解决不了不可重复读因为RC下每次查询都会生成新的快照新快照会包含其他事务已经提交的修改所以两次查询可能读到不同版本的数据自然解决不了不可重复读。而RR下快照只拍一次全程复用不管其他事务怎么改都不影响当前事务的读取结果这就是MVCC解决不可重复读的关键。四、避坑简单总结避坑1不要以为MVCC能解决所有问题——它只解决RR隔离级别下的不可重复读RC下不行也解决不了幻读幻读是另一个问题新手暂时不用管避坑2记住MVCC的核心是“多版本数据快照”不用去深究版本链怎么实现、快照怎么存储新手先懂逻辑就够了避坑3RC和RR下MVCC的差异只看“快照生成时机”就够了不用记其他复杂区别。最终总结1. 差异RC下MVCC每次查询拍新快照会出现不可重复读RR下MVCC只拍一次快照全程复用不会出现不可重复读2. MVCC解决不可重复读的核心RR隔离级别下通过“单快照数据版本链”让同一个事务全程读同一个数据版本不受其他事务修改影响3.RC多快照可重复读失效RR单快照可重复读生效

更多文章