关系数据库:"Dirty Writes" 到底是什么?如果他们不被允许会怎样?

Relational Database: What exactly are "Dirty Writes"? What happens if they are not allowed?

目前我阅读了有关数据库隔离级别和事务现象的信息。 脏读很明显,但 我不确定 "Dirty Writes"

"dirty write" 的所有描述都是这样的:

"A dirty write is when a process save a file data that has already been changed on disk by another process. The last process will then overwrite the data of the first one." (https://gerardnico.com/data/property/dirty_write).

其他一些描述使用示例来演示 "dirty write" 但不是解决该问题的方法:https://esb-dev.github.io/mat/IsoLevel.pdf


这是示例中的脏写:

  1. Saldo 以 100 开头
  2. T2 开始:更新账户设置 Saldo = 200,其中账户 = 1
  3. T1 开始:更新账户设置 Saldo = 250,其中账户 = 1
  4. T1 提交 => Saldo=250
  5. T2 提交 => Saldo=200

我不确定当隔离级别不允许时会发生什么 "dirty writes" ...

我真的不确定我应该对事务管理有什么期望。


示例,修改:

  1. Saldo 以 100 开头
  2. T1 开始:更新账户设置 Saldo = 200,其中账户 = 1
  3. T2 开始:更新账户设置 Saldo = 250,其中账户 = 1
  4. T2 提交 => Saldo=?
  5. T1 提交 => Saldo=?

我们这里有脏写吗?如果允许脏写,结果是什么?


我还有一个关于 Java/Spring JPA/Hibernate

的问题

以前我希望写入语句不会被发送到数据库,除非 hibernate 执行 "commit"。我错了吗?某些隔离级别和现象只有在所有语句始终立即传输到数据库时才有意义。

通常,t运行saction 通过锁定将要写入的行直到 t运行saction 结束来防止脏写。这意味着 t运行saction 都不会失败,只是第二次写入会延迟到第一个 t运行saction 完成。我认为没有任何隔离级别不这样做。

因此,当您想到脏写时,您可以想象没有任何隔离。在您的第一个示例中,我希望 Saldo 的最终帐户为 250,因为对 200 的更新已被覆盖。

请注意,一个 t运行saction 覆盖另一个 t运行saction 的写入不一定是问题。即使我们想象两个 t运行saction 运行 连续(即第一个 t运行saction 中的所有内容在第二个 t运行saction 开始之前完成)因此完全隔离我们仍然期望一个 t运行saction 覆盖另一个 t运行saction.

我认为脏写的一个更好的例子是如果 t运行saction A 和 B 都尝试写入第 1 行和第 2 行,但 t运行saction A 最后写入行1 和 t运行saction B 最后写入第 2 行。然后你会看到一个不符合我们对隔离的期望的结果。

举一个具体的例子,你可以想象你有两行分别代表一场比赛的第一名和第二名。第一个 t运行saction 将赛车手 1 设置为第一,将赛车手 2 设置为第二。片刻之后,第二个 t运行saction 想要更新以将赛车手 2 放在第一位,将赛车手 1 放在第二位。如果脏写是可能的,那么您最终可能会在第一名和第二名的插槽中获得赛车手 1(或赛车手 2)。

正如我已经提到的,您可以通过使用任何隔离级别的 t运行saction 来解决这个问题,这将锁定正在写入的行,防止被任何其他 t运行saction 写入直到提交更改。

不允许脏写。您的示例的问题是尝试更新行的第二个事务首先提交。但实际上并非如此。第一个更新语句阻塞该行,直到第一个事务结束。第二笔交易应该等待。