隔离级别:脏写和丢失更新之间的区别

Pat*_*ick 6 sql database transactions dirty-write lost-update

我正在阅读《ANSI SQL 隔离级别批判》 ,并对这两个定义感到困惑:

脏写

w1[x]...w2[x]...((c1 或 a1) 和 (c2 或 a2) 任意顺序)

丢失更新

r1[x]...w2[x]...w1[x]...c1

丢失更新的历史定义不包括脏写吗?(w2[x]...w1[x] 部分)。如果是,那么如果我们防止脏写,我们就可以防止丢失更新,对吗?我知道这显然是错误的,但我不明白为什么。谁能对我在这里误解的内容给出一些提示?非常感谢!

我找到了解释这个例子的文章

在此输入图像描述

由于 T2 在 T1 写入 x 之前提交,因此不存在脏写。

但是丢失更新的定义并不要求第二次写入发生在第一个事务提交之后,对吧?

小智 5

  • 脏写是指一个事务更新或删除(覆盖)其他事务插入、更新或删除的未提交的数据。*基本上,许多数据库中的所有隔离级别都不会发生脏写。

  • 丢失更新是指两个事务读取同一行并对其进行更新,但第一个提交的更新被第二个提交的更新覆盖。*基本上,许多数据库的隔离级别不会发生丢失更新,并且在MySQLPostgreSQL中使用可以防止丢失更新SERIALIZABLESELECT FOR UPDATE

脏写丢失更新的区别在于未提交的数据被覆盖或已提交的数据被覆盖。

例如,有一个带有,和product的表,如下所示。*当顾客购买产品时,产品的库存会减少。idnamestock

product桌子:

ID 姓名 库存
1 苹果 10
2 橙子 20

下面的这些步骤显示了脏写

流动 交易1(T1) 交易2(T2) 解释
步骤1 BEGIN; T1开始。
第2步 BEGIN; T2开始。
步骤3 SELECT stock FROM product WHERE id = 2;

20
T1 读取20内容稍后更新为,13因为客户购买了 7 个橙子。
步骤4 SELECT stock FROM product WHERE id = 2;

20
T2 读取20稍后更新为,16因为客户购买了 4 个橙子。
步骤5 UPDATE product SET stock = '13' WHERE id = 2; T1 更新2013.
步骤6 UPDATE product SET stock = '16' WHERE id = 2; T2 更新1316T1 提交之前。

*发生脏写。

步骤7 COMMIT; T1 提交。
步骤8 COMMIT; T2 提交。

以下步骤显示丢失的更新

流动 交易1(T1) 交易2(T2) 解释
步骤1 BEGIN; T1开始。
第2步 BEGIN; T2开始。
步骤3 SELECT stock FROM product WHERE id = 2;

20
T1 读取20内容稍后更新为,13因为客户购买了 7 个橙子。
步骤4 SELECT stock FROM product WHERE id = 2;

20
T2 读取20稍后更新为,16因为客户购买了 4 个橙子。
步骤5 UPDATE product SET stock = '13' WHERE id = 2; T1 更新2013.
步骤6 COMMIT; T1 提交。
步骤7 UPDATE product SET stock = '16' WHERE id = 2; T2 更新1316T1 提交后。
步骤8 COMMIT; T2 提交。

*发生丢失更新。