MVCC 读取快照为什么还有幻读

1. MVCC 快照的机制
MVCC 为每个事务提供了一个一致性视图(Consistent View),这个视图是事务开始时数据库的一个快照。
事务 A 的快照是在事务 A 开始时创建的,它只会包含事务 A 开始时已经提交的数据。
事务 B 的插入操作是在事务 A 开始之后发生的,因此这些新数据不会出现在事务 A 的快照中。

2. 事务 B 插入新数据的影响
事务 B 插入的新数据会写入数据库,但这些数据对事务 A 是不可见的,因为事务 A 的快照已经固定。
即使事务 B 提交了插入操作,事务 A 仍然看不到这些新数据,因为 MVCC 保证了事务 A 的快照一致性。

3. 为什么会有幻读
幻读的本质是范围查询的结果集发生变化,而不是快照本身的变化。
事务 A 的 MVCC 快照不会变化,但如果事务 A 执行的是范围查询(如 SELECT ... WHERE id BETWEEN 10 AND 20),而事务 B 在事务 A 的查询范围内插入了新数据,那么事务 A 的查询结果可能会发生变化。
这是因为范围查询是动态的,它会根据当前数据库的状态返回结果,而不仅仅是快照中的数据。

5. MVCC 快照与幻读的关系
MVCC 快照保证了事务 A 看到的数据是它开始时的状态,但范围查询是动态的,它会根据当前数据库的状态返回结果。
事务 B 插入的新数据不会出现在事务 A 的快照中,但会影响事务 A 的范围查询结果,从而导致幻读。

 

6. 如何避免幻读
使用间隙锁(Gap Lock):
在可重复读隔离级别下,InnoDB 会对范围查询中的间隙加锁,防止其他事务插入新数据。
提高隔离级别:
将隔离级别提高到串行化(Serializable),可以完全避免幻读,但会牺牲并发性能。

总结
事务 A 的 MVCC 快照不会因为事务 B 的插入操作而发生变化。
幻读的本质是范围查询的结果集发生变化,而不是快照本身的变化。
为了避免幻读,可以使用间隙锁或提高隔离级别。

posted @ 2025-03-19 11:19  随笔~~~~~~  阅读(50)  评论(0)    收藏  举报