不可重复读是指同一事务内多次读取同一行数据结果不一致,因其他事务修改并提交了该数据;MySQL通过REPEATABLE READ隔离级别配合MVCC快照读可避免,而READ COMMITTED每次读取新快照导致不可重复读。

不可重复读是指在一个事务内,对同一行数据进行多次读取时,得到的结果不一致的现象。根本原因是:其他事务在该事务执行期间修改并提交了这行数据,导致后续读取“看到”了已提交的变更。
不可重复读发生的典型场景
以银行账户余额查询为例:
- 事务A开启,第一次查询用户U的余额为1000元
- 事务B将用户U余额更新为1200元,并成功提交
- 事务A再次查询同一用户余额,结果变为1200元
- 两次读取结果不同,且中间无回滚——这就是不可重复读
和脏读的关键区别
不可重复读读到的是已提交的数据,而脏读读到的是未提交、可能被回滚的数据:
技术上面应用了三层结构,AJAX框架,URL重写等基础的开发。并用了动软的代码生成器及数据访问类,加进了一些自己用到的小功能,算是整理了一些自己的操作类。系统设计上面说不出用什么模式,大体设计是后台分两级分类,设置好一级之后,再设置二级并选择栏目类型,如内容,列表,上传文件,新窗口等。这样就可以生成无限多个二级分类,也就是网站栏目。对于扩展性来说,如果有新的需求可以直接加一个栏目类型并新加功能操作
- 脏读:事务B读到了事务A还没提交的修改,A若回滚,B就拿到了无效值
- 不可重复读:事务B读到了事务A已提交的修改,数据真实存在,但破坏了本事务内读取的一致性
MySQL中如何避免不可重复读
MySQL默认隔离级别 REPEATABLE READ(可重复读) 就是专门解决这个问题的:
- 它基于MVCC(多版本并发控制),为事务启动时生成一个一致性视图(Read View)
- 整个事务期间都按这个快照读取数据,即使其他事务已提交修改,本事务仍看到原始值
- 因此,在RR级别下,上面例子中事务A两次查询都会返回1000元,不会出现不可重复读
为什么READ COMMITTED级别无法避免
在READ COMMITTED(读已提交)隔离级别下:
- 每次SELECT都会新建Read View,读取最新已提交版本
- 所以事务A第一次查是1000,事务B提交后,事务A第二次查就会变成1200
- 这种“每次读都刷新快照”的行为,正是不可重复读产生的直接原因









