你真的明白什么是幻读吗?
导读:幻读是指当事务不是独立执行时发生的一种现象。很多程序员虽然工作多年,但是对幻读依然了解的不够。本文作者分析了幻读出现的一般原因,并对数据库的处理策略做了总结。
数据库事务由4ACID定义的。隔离级别(ACID中的I)是允许用户指定数据完整的折中方案。隔离级别越弱,产⽣问题的可能性越多。这里我们讲一下幻读问题。
并发事务的数据更新
如果⼀个事务基于给定的数据列集合做业务决策,而没有范围锁,一个并发的事务可能会导致新增一⾏记录,引发这种特殊的情况。
在上图中,流程如下:
Alice和Bob开启了数据库的两个事务;
Bob读取post_comment表中所有post_id为1的数据;
Alice增加了一条post_id为1的数据;
Alice提交了她的事务;
如果Bob重复读取post_id为1的数据,他将发现不一样的结果集;
如果当前事务基于第一次返回的结果做了业务决策,那么就会产生问题。
数据库如何防止这种现象
SQL标准这么定义幻读,在两个连续的查找之间一个并发的修改事务修改了查询的数据集,导致这两个查询返回了不同的结果。
尽管提供读一致性是可序列化的强制要求,但是还不够。例如,一个买家可能购买产品⽽不知道在他提交订单之后的瞬间,商品有更低的报价。
两阶段加锁(2PL-based)序列化隔离使用谓词锁,通过访问MVCC数据库引擎返回的快照,来防止幻读。
尽管如此,并发的事务仍然有可能修改被读取过的数据。甚⾄MVCC数据库引擎实现了事务调度,不同的请求通过两阶段加锁实现依然可能返回不同的结果。例如,第2个事务添加了一条记录,不在第1个事务的读取记录中。在这种特殊的应⽤场景中,很多MVCC数据库引擎将不会回滚前⾯的事务。