mysql可重复读(rr)靠mvcc实现,事务启动时创建唯一readview并复用,通过db_trx_id与m_ids、min_trx_id、max_trx_id比较判断版本可见性,配合undo log版本链回溯;与rc区别在于readview复用而非每次重建,当前读不走快照需间隙锁防幻读。

MySQL 的可重复读(Repeatable Read,RR)隔离级别,核心就是靠 MVCC 实现的。它不是靠锁住整张表或行来“冻结”数据,而是让每个事务在开始时拍下一张“快照”,后续所有普通 SELECT 都基于这张快照读取,从而保证同一事务内多次查询结果一致。
关键在于:快照只生成一次,且贯穿整个事务
事务启动后(即第一次执行增删改查语句时),InnoDB 会立即创建一个 ReadView —— 这就是它的“一致性视图”。这个 ReadView 包含:
-
m_ids:创建时刻所有活跃(已开启、未提交)事务的 ID 列表 -
min_trx_id:m_ids中最小的事务 ID -
max_trx_id:系统下一个将分配的事务 ID(即当前最大已用 ID + 1) -
creator_trx_id:当前事务自己的 ID
之后事务内的所有快照读(普通 SELECT),都用这个同一个 ReadView 去判断每一行数据的哪个版本可见。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
怎么判断某行是否可见?看它的 DB_TRX_ID(最近修改该行的事务 ID)和 ReadView 比较:
- 若
DB_TRX_ID :该版本由早于快照创建前就已提交的事务生成 → 可见 - 若
DB_TRX_ID >= max_trx_id:该版本由快照创建后才启动的事务生成 → 不可见 - 若
min_trx_id : <ul> <li>如果 <code>DB_TRX_ID在m_ids列表中 → 是未提交的活跃事务写的 → 不可见 - 如果
DB_TRX_ID不在m_ids中 → 是已提交但晚于快照创建时间的事务写的 → 仍不可见(RR 要求只认快照前已提交的版本)
版本链配合 undo log 回溯
每行数据通过 DB_ROLL_PTR 指向 undo log 中的上一个版本,形成一条版本链。当当前版本不可见时,就顺着回滚指针往前找,直到找到一个满足上述可见性规则的版本为止。
和读已提交(RC)的区别就在这里
RC 每次 SELECT 都重新生成 ReadView,所以能“看到”其他事务刚提交的新数据;而 RR 只在事务开始时建一次,后面无论其他事务如何提交,只要没进它的初始 m_ids,就一律“视而不见”。
注意:当前读不走 MVCC 快照SELECT ... FOR UPDATE、UPDATE、DELETE 等操作属于当前读,它们总是读最新已提交版本,并加锁,不受 ReadView 限制。这也是为什么在 RR 下仍可能发生幻读——新插入的记录虽不在快照里,但当前读能感知到,需配合间隙锁(Gap Lock)来解决。
不复杂但容易忽略










