有人可以解释一下数据库事务理论中“写入偏差”和“丢失更新”之间的区别吗?有人可以给我一个例子吗?
1 回答
非正式地,丢失更新和写入偏差是并发写入事务可能相互干扰的方式。
当基于陈旧数据在事务中进行更新时,会发生写入偏差。 陈旧数据是由事务读取的值,该值由于并发事务的后续提交写入而变得陈旧。
当一个事务写入的已提交值被来自并发事务的后续已提交写入覆盖时,就会发生丢失更新。实际上,丢失更新确实是write skew的一个特例;更新应用于已过时的数据。
考虑零售商店的数据库维护Inventory表的情况。数据库没有实现事务隔离。
Inventory表有一个“ProductId”列和一个“InStock”列,用于计算特定产品当前库存的项目数。每次购买(交易)都会将“InStock”值减去购买的商品数量。
想象一下,商店有两个电动剃须刀(特定型号的)库存。
两位顾客同时购买其中一款剃须刀。
每个并发购买(交易)从剃须刀的“InStock”记录中读取相同的值(两个)。每个事务都会递减“InStock”计数器并将更新的值(一)提交到数据库。在两个并发事务都提交后,计数器将错误地指示剃须刀仍有库存(剩余一件)。
其中一个更新丢失了。
假设数据库实现了快照隔离(带有丢失更新检测),在这种情况下丢失更新不会发生。这是因为快照隔离检测何时发生丢失更新。在事务提交数据后,尝试提交对相同数据的写入的并发事务将被数据库中止。在我们的示例中,事务被中止的进程启动一个新事务以重新读取“InStock”列,将其递减,并提交更新的值。假设没有其他冲突,此更新记录的尝试成功提交,并且“Instock”列包含(正确)值零。
此外,假设数据库在InventoryHistory表中记录库存历史。InventoryHistory表具有列“Timestamp”、“ProductId”和“InStock”(购买后剩余)。按照设计,对InventoryHistory表的更新是采购交易中的最后一个操作。在两个事务提交后,各自的InventoryHistory记录将分别反映“Instock”值 1 ——这是不正确的,因为其中一个记录应该反映“Instock”值为零。不正确的InventoryHistory记录是write skew的一个示例。
在这种情况下,快照隔离并没有阻止异常数据被写入数据库,因为没有更新丢失。相反,写入的数据是异常的,因为事务读取的值已经过时——这就是write skew。 快照隔离并不能防止写入偏差。为了防止写入倾斜,数据库必须实现可序列化的隔离。
阅读这篇文章,详细讨论写入偏差、可串行化和快照隔离。