为什么必须以倒序取消未提交的事务?


19

我有一个数据库日志,其中有一些事务获胜(它们在崩溃之前已提交)和一些事务(尚未提交)。我们在课堂上了解到,失败者的行为必须向后撤消。

有什么理由倒退吗?谁能给出一个简单的日志示例,其中正向撤消操作将导致错误的结果?


难道不应该在另一个更具体的网站上问这个问题吗?
nbro

Answers:


35

原始交易:

  1. 插入记录[R
  2. 更新一些领域[R F[R

转发撤消:

  1. 删除记录[R
  2. 将更新撤消到等等,r不再存在!这会导致错误。[R[R

如果系统可以弄清楚事物需要回滚到什么状态并可以在处理其他任何事物之前应用所有必要的更改,那么是否需要以相反的顺序在物理上逐个撤消操作?
超级猫

11
以相反的顺序撤消更改很容易。你为什么要努力让自己受苦呢?
gnasher729

1
不,系统不会做所有事情,但仍会以倒序的方式解决。
Evil

3
在许多现实世界的数据库系统中,由于表上的关键约束,甚至不可能以相反的顺序进行操作。
SeanR '16

11

要增加DylanSp的答案,尝试更新不存在的记录中的字段将失败,但是结果仍将是预期的结果:记录r不存在。

但是,请考虑删除记录实际上将失败的情况:

  1. 插入订单O。
  2. 插入订单行L。

让我们(并非不现实地)假设每个OrderLine 必须与一个Order相关。

现在,从删除订单开始回滚事务将失败,因为这将违反我们的业务规则。

所以之后

  1. 删除订单O。(失败)
  2. 删除OrdelineL。(成功)

我们可能会以现有订单(没有订单行)结束。

当然,在这种情况下,我们可以使用级联删除,但这将意味着步骤2将失败(无影响)。更糟糕的是,对订单实施级联删除可能是不受欢迎的行为。


好的,这很有道理。
谢谢

假设在“正常”情况下交易之前或之后没有违反约束条件是否合适?通常,我的意思是,如果只有一个人使用数据库,则交易不会失败。如果是这样,为什么在撤消过程中不引入约束违规很重要?似乎可以在撤消操作开始时关闭约束,并在操作完成后启用约束。
Noctis Skytower

2
@NoctisSkytower在常规I / O操作期间关闭约束会使它们变得无用。它们存在是有原因的。我的示例清楚地说明了在正常情况下如何满足约束,而回滚期间却违反了约束。在回滚期间关闭约束会不必要地使事情复杂化,并解决了错误的问题。问题不是约束,问题是通过错误地尝试回滚而违反了约束。
oerkelens

是的,这很有意义,但是为什么在回滚期间检查约束?假定回滚旨在保证没有问题地完成,为什么如果知道回滚完成时不会违反约束,为什么会不必要地浪费时间检查约束呢?顺便说一句,这应该是一个保证,因为如果回滚失败,则数据库似乎需要前滚,而前滚是做不到的。
Noctis Skytower

1
@NoctisSkytower,即使是临时状态,数据库也永远不可能处于违反约束的状态。如果整个回滚是原子的,那么它的顺序无关紧要,因为没有顺序,这是一条指令“一次全部发生”。如果有两个或多个事务以某种顺序分别回滚,则该顺序是强制性的,以使任何读取中间数据的观察者只能看到所有约束都成立的情况。
彼得尼斯(Peteris)2016年

6

打个比方:假设您要出去吃晚餐。

  1. 穿袜子。
  2. 穿鞋。
  3. 站起来。
  4. 走到门。

然后,您会接到一个电话。晚餐计划被取消。

  1. 脱袜子。
  2. 脱鞋。
  3. 坐下。
  4. 从门走开。

那里出问题了。您可能会绊倒并伤到自己。或更可能的是,您将意识到某些操作只有先撤消以后的操作才能撤消。

撤消您正在做的最后一件事,可让您回到发生下一个步骤时的状态。然后,您撤消该步骤并重复,然后移回直到什么都没有剩下。另一方面,鉴于后续步骤之后的状态,第一步可能无法逆转。

从数学上讲:动作可能不会改变,因此无论您在第一步或第二步中哪个步骤重要,撤消步骤的顺序都会很重要。


3

这是正确的,因为事务是建立在彼此之上的,并且事务的结果在很大程度上取决于提交之前的情况。

让我们看一下金融交易:

(开始时,在交易a欠我100美元之前)

  1. a 欠我100美元(现在总负债200)
  2. a欠他10%的折扣。(现在总债务为180)

假设我要取消两项交易。

如果我们取消第一个,我们将得到:

  1. 较低的债务100(现在有债务80)
  2. 取消10%的折扣(现在有80 / 0.9 = 88的债务)

这是错误的,我们需要回到100的债务。如果我们以相反的顺序取消交易,那将是正确的。

  1. 取消折扣-现在债务为200
  2. 降低100债务-现在债务为100

2

假设有一个仅包含一列的表T。

假定“撤消日志”是一个包含未提交事务的数据库文件,并且“重做日志”是一个包含尚未应用到数据文件的未提交事务和已提交事务的数据库文件。

At 8:00 A.M., Transaction 100 inserts rows with values 101, 102 and 103 into table T. At 8:10 A.M., Transaction 100 is committed and the commit for transaction 100 completes. At 8:15 A.M., Transaction 200 updates row 101 to 201, 102 to 202 and 103 to 203. At 8:20 A.M., Transaction 200 has not been committed and remains in the undo log of the database. At 8:25 A.M., Transaction 300 increments each row by 50, changing row 201 to 251, 202 to 252, and 203 to 253. At 8:30 A.M., Transaction 300 has not been committed and remains in the undo log of the database. At 8:35 A.M., The instance providing access to the database crashes.

At 8:40 A.M., The instance is restarted, and the database files are opened as the instance is started:

              The committed values in T are still 101, 102 and 103.

              Since 201, 202, and 203, and 251, 252 and 253
              are not committed, if they are written into the "redo
              log" of the database, there is a need to "roll back"
              the transactions AFTER the "redo log" is applied.

              Since 201, 202, and 203, and 251, 252 and 253
              are not committed, they are in the "undo log"
              of the database.

              The undo log of the database is used BOTH to (1) roll
              back a transaction that is deliberately rolled 
              back in the memory structure of the database instance, 
              and also (2) during the instance recovery at 8:40 A.M.

At 8:41 A.M., The redo log has been applied, and the T table contains values 251, 252 and 253 in the instance memory.

              The undo log has not yet been applied.

At 8:42 A.M., The undo log is applied in the reverse order: Uncommitted transaction 300 is undone, and Uncommitted transaction 200 is undone.

为什么将已提交和未提交的事务都写入重做日志文件? 这样做的原因是提供时间点恢复。

这意味着“重做日志”文件的内容与事务不一致。 因此,无论何时使用重做日志将已提交的事务应用于数据文件,都必须使用“撤消日志”来回滚未提交的事务。

为什么“撤消日志”中的事务以相反的顺序回滚?事务300已经将50增加到每一行的每一列的现有值。因此,如果事务200首先回滚,则值将从251、252和253更改为201、202和203。如果事务300然后最后回滚,则值将为151、152和153-不匹配原始承诺值。

参考资料:

https://asktom.oracle.com/pls/asktom/f?p=100:11:0:::::P11_QUESTION_ID:1670195800346464273


0

这不是天生的真实。回滚可以简单地重新应用撤消日志中缓存的块,以便最终状态与初始状态相同。由于日志是按前进顺序编写的,因此我的回滚也适用于前进顺序。顺序无关紧要,因为在日志文件标记为已解决之前,将重试回滚。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.