数据库事务:“写入偏差”和“丢失更新”之间的区别
Posted
技术标签:
【中文标题】数据库事务:“写入偏差”和“丢失更新”之间的区别【英文标题】:Database Transactions: Difference between 'write skew' and 'lost update' 【发布时间】:2015-01-07 19:01:46 【问题描述】:谁能解释一下“写偏斜”和“写偏斜”之间的区别 数据库事务理论中的“丢失更新”? 谁能举个例子?
【问题讨论】:
【参考方案1】:非正式地,丢失更新和写入偏差是并发写入事务可能相互干扰的方式。
写入偏差发生在基于陈旧数据的事务中进行更新时。 陈旧数据是一个事务读取的值,由于并发事务的后续提交写入而变得陈旧。
丢失更新发生在一个事务写入的已提交值被来自并发事务的后续已提交写入覆盖时。其实lost update确实是write skew的特例;将更新应用于已过时的数据。
考虑零售商店的数据库维护 Inventory 表的情况。数据库没有实现事务隔离。
Inventory 表有一个“ProductId”列和一个“InStock”列,用于计算特定产品的当前库存商品数量。每次购买(交易)都会使“InStock”值减少所购买商品的数量。
假设商店有两台电动剃须刀(特定型号的)库存。
两位客户同时购买其中一款剃须刀。
每个并发购买(交易)从剃须刀的“InStock”记录中读取相同的值(两个)。每个事务都会递减“InStock”计数器并将更新的值(一)提交到数据库。在两个并发事务都提交后,计数器将错误地指示剃须刀仍有库存(剩余一件)。
其中一个更新丢失。
假设数据库实现了快照隔离(带有丢失更新检测),在这种情况下丢失更新不会发生。这是因为快照隔离会检测到丢失更新的时间。在事务提交数据后,尝试提交对相同数据的写入的并发事务将被数据库中止。在我们的示例中,事务被中止的进程启动一个新事务以重新读取“InStock”列,将其递减,并提交更新的值。假设没有其他冲突,此更新记录的尝试成功提交,并且“Instock”列包含(正确)值零。
Transaction isolation is a deep topic.
进一步假设数据库在InventoryHistory 表中记录库存历史。 InventoryHistory 表具有“Timestamp”、“ProductId”和“InStock”列(在购买后)。 按照设计,对 InventoryHistory 表的更新是购买交易中的最后一个操作。在两个事务提交后,各自的 InventoryHistory 记录将各自反映“Instock”值 1——这是不正确的,因为其中一条记录应该反映“Instock”值为零。不正确的 InventoryHistory 记录是 write skew 的一个示例。
在这种情况下,快照隔离并没有阻止异常数据写入数据库,因为没有更新丢失。相反,写入的数据是异常,因为事务读取的值已经过时——这是写入偏差。 快照隔离不会阻止写入偏斜。为了防止write skew,数据库必须实现可序列化的隔离。
Read this article 对写入偏差、可串行化和快照隔离进行了严格的讨论。
【讨论】:
我不认为将丢失更新描述为写入偏斜的特殊情况是完全正确的。在学术界,这些被认为是不同的情况,因为您可以有意义地说数据库系统通过快照隔离来防止丢失更新,而不是写入倾斜。如此处所述:jepsen.io/consistency/models/snapshot-isolation 回想起来,我只是有点困惑,因为我读过快照隔离允许写入倾斜,但不会丢失更新。对未来读者的一些澄清:写入偏斜涉及写入不相交的字段集的并发事务。丢失更新涉及写入重叠变量集的并发事务。以上是关于数据库事务:“写入偏差”和“丢失更新”之间的区别的主要内容,如果未能解决你的问题,请参考以下文章