数据库事务:'写入偏差'并且“失去了更新”#39;

时间:2015-01-07 19:01:46

标签: sql database transactions snapshot-isolation

有人可以向我解释一下'写错误'之间的区别。和a '丢失更新'在数据库事务理论? 有人可以举个例子吗?

1 个答案:

答案 0 :(得分:0)

非正式地,丢失更新写入偏斜是并发写入事务可能相互干扰的方式。

写偏斜是在基于陈旧数据的事务中进行更新时发生的。 陈旧数据是由事务读取的值,由于后续从并发事务中提交的写入操作,该值已变得陈旧。

丢失更新会发生,当一个事务写入的承诺值被并发事务中的后续提交写入覆盖时。实际上,丢失更新实际上是写偏斜的一种特殊情况;将更新应用于已过时的数据的地方。

考虑零售商店的数据库维护库存表的情况。数据库未实现事务隔离

库存表具有一个“ ProductId”列和一个“ InStock”列,该列计算特定产品当前的库存数量。每次购买(交易)都会使“ InStock”值减少所购买商品的数量。

想象一下,商店中有两把(特定型号的)电动剃须刀库存。

两个客户各自同时购买这些剃须刀之一。

每个并发购买(交易)从剃须刀的“ InStock”记录中读取相同的值(两个)。每个事务减少“ InStock”计数器,并将更新后的值(一个)提交到数据库。在完成两个并发事务后,计数器将错误地指示剃须刀仍然有库存(剩余一件)。

更新之一丢失

假设数据库实现了快照隔离(具有丢失更新检测),在这种情况下不会发生丢失更新。这是因为快照隔离检测到何时发生丢失的更新。事务提交数据之后,数据库将中止尝试提交同一数据写入的并发事务。在我们的示例中,中止交易的流程启动了一个新交易,以重新读取“ InStock”列,将其递减并提交更新后的值。假定没有其他冲突,则此尝试更新记录的尝试将成功提交,并且“库存”列包含(正确)值零。

Transaction isolation is a deep topic

此外,假定数据库在 InventoryHistory 表中记录库存历史记录。 InventoryHistory 表具有“ Timestamp”,“ ProductId”和“ InStock”列(购买后的 )。 根据设计,对 InventoryHistory 表的更新是购买交易中的最后一项操作。在两次提交事务之后,各自的 InventoryHistory 记录将各自反映“库存”值为1 -这是不正确的,因为其中一条记录应反映为“ Instock”值为零。错误的 InventoryHistory 记录是写入偏斜的示例。

在这种情况下,快照隔离不能防止将异常数据写入数据库,因为没有更新丢失。相反,写入的数据是异常,因为该事务读取的值已经过时-这是写入偏斜快照隔离不会阻止写入偏斜。为了防止写入偏斜,数据库必须实现可序列化的隔离。

Read this article对写入偏斜,可串行化和快照隔离进行了严格的讨论。