外观
可重复读解决了什么问题?
⭐ 题目日期:
字节 - 2024/12/17
📝 题解:
MySQL 的 可重复读(Repeatable Read) 隔离级别主要解决了以下两类并发事务问题:
1. 脏读(Dirty Read)
- 问题:事务 A 读取了事务 B 未提交的修改,若事务 B 回滚,事务 A 读到的数据是无效的。
- 解决:在可重复读隔离级别下,事务只能读取其他事务 已提交 的数据。
2. 不可重复读(Non-Repeatable Read)
- 问题:事务 A 多次读取同一数据,事务 B 在此期间修改并提交了该数据,导致事务 A 前后读取结果不一致。
- 解决:通过 多版本并发控制(MVCC),事务 A 在生命周期内看到的是 一致性视图(快照),不受其他事务提交的影响。
3. 幻读(Phantom Read)(MySQL 增强解决)
- 问题:事务 A 读取某个范围的数据后,事务 B 插入或删除了该范围内的数据,导致事务 A 再次读取时出现“幻影行”。
- 解决:MySQL 在可重复读隔离级别下,通过 Next-Key Locks(行锁 + 间隙锁)锁定查询范围,禁止其他事务插入或删除范围内的数据。
4. 实现原理
- MVCC(多版本并发控制):
- 每个事务启动时分配一个唯一的事务 ID(
tx_id
)。 - 每条记录包含隐藏字段
DB_TRX_ID
(最后修改该记录的事务 ID)和DB_ROLL_PTR
(回滚指针,指向历史版本)。 - 事务只能读取
DB_TRX_ID
小于等于自身tx_id
且已提交的记录。
- 每个事务启动时分配一个唯一的事务 ID(
- Next-Key Locks:
- 锁定索引记录和间隙(例如
WHERE id > 10
,锁定(10, +∞)
范围),防止其他事务插入或删除。
- 锁定索引记录和间隙(例如
5. 对比其他隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现机制 |
---|---|---|---|---|
读未提交 | ✔️ | ✔️ | ✔️ | 无锁,直接读最新数据 |
读已提交 | ❌ | ✔️ | ✔️ | MVCC,每次读最新提交数据 |
可重复读(默认) | ❌ | ❌ | ❌(MySQL 解决) | MVCC + Next-Key Locks |
串行化 | ❌ | ❌ | ❌ | 所有操作加锁,完全串行 |
6. 适用场景
- 可重复读的典型场景:
- 需要事务内多次读取同一数据的一致性(如对账、统计)。
- 允许高并发但需避免幻读(如订单状态更新)。
- 不适用场景:
- 对数据实时性要求极高(需用读已提交)。
- 极高频写入导致锁竞争激烈(需权衡一致性)。
7. 总结
- 解决的问题:
- 脏读:确保事务只读已提交的数据。
- 不可重复读:通过 MVCC 提供一致性视图。
- 幻读(MySQL 增强):通过 Next-Key Locks 锁定范围。
- 核心优势:在并发性能和数据一致性之间取得平衡,是 MySQL InnoDB 默认隔离级别的原因。