暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【数据库理论】事务的调度(二):可恢复性

原创 Hominid⁺ 2025-07-22
90

可恢复性和可串行化

        可串行化是数据库事务的一个重要属性,而可恢复性则是其另外一个同等重要的属性。对调度和可串行化的理解,可以参考 【数据库理论】事务的调度(一):可串行化可串行化 要求多个事务并发执行的效果等价于某个串行执行的效果,它保证的是 事务的执行顺序 不会影响数据一致性。而 可恢复性 要求事务在发生故障或错误时数据库系统可以恢复到一致的状态,它保证的是 事务提交或终止顺序 不会影响数据一致性;

        可串行化和可恢复性没有直接的关系。无论是可串行化调度,还是不可串行化调度,都可能会出现不可恢复的问题。而可恢复调度可能是可串行化调度,也可能是是不可串行化调度。所以 DBMS 在进行事务调度时,不仅需要保证调度是可串行化的,还要保证调度是可恢复的;

脏读和可恢复调度

脏读的示例

(根据 《A Critique of ANSI SQL Isolation Levels》 论文的描述,脏读指的是:事务 T1 修改了一个数据项,而事务 T2 在 T1 提交或回滚前读取了该数据项,即“读未提交”,这里需要特别注意一下,这里对脏读的定义是预防性定义 P1,指的是可能会导致脏读的全部情况。而脏读的严格性定义 A1 指的是一定会导致脏读的情况)

        调度可能会因为脏读,出现无法恢复的问题,比如:

T1 T2
Read(A)
Write(A)
Read(A)
Commit
Rollback
  1. 事务 T2 读取了事务 T1 修改的数据项 A,并先提交;
  2. 随后事务 T1 开始进行回滚,导致事务 T2 读取的是无效值,所以 T2 也需要被回滚,但 T2 已经提交无法再回滚,所以该调度是不可恢复的(如果允许事务 T2 回滚,则违背了 ACID 属性中的持久性 Durability。对 ACID 的理解,可以参考【数据库理论】事务 - ACID 属性);

        但如果事务 T1 在 T2 提交前终止,则事务 T2 就是可以被回滚的,所以以下调度是可恢复的:

T1 T2
Read(A)
Write(A)
Read(A)
Rollback
Commit

问题分析

        调度无法恢复的原因在于产生脏读的事务先提交,而事务一旦提交就无法被回滚。所以解决方案就是对事务的提交顺序进行限制,要求读取未提交数据的事务必须后提交。

解决方案

        可恢复调度(Recoverable Schedule) 就可以解决调度无法恢复的问题,其限制如下:

对于某个调度而言,如果它其中的任意一对事务 T1 和 T2 都满足:如果 T2 读取了先前由 T1 修改的数据项,那么 T1 必须比 T2 先提交。

      不满足上述要求的调度则被称为 不可恢复调度(Non-Recoverable Schedule) 。换句话说,可恢复调度需要保证事务一旦提交,就不再需要再被回滚,这也是为了保证事务的持久化属性不被破坏。所以如果某个调度存在已提交的事务在恢复过程中需要被回滚的情况,则该调度就是不可恢复调度;

级联回滚和无级联调度

级联回滚的示例

        可恢复调度可能会出现 级联回滚(Cascading Rollback) 的问题,比如:

T1 T2 T3
Read(A)
Write(A)
Read(A)
Write(A)
Read(A)
Rollback
Commit
Commit
  1. 上述调度满足可恢复调度的要求:T3 读取了 T2 修改的数据,T2 读取了 T1 修改的数据,而 T1 比 T2 先回滚,T2 比 T3 先提交;
  2. 但其中 T3 读取了由 T2 修改的数据,T2 读取了由 T1 修改的数据,一旦 T1 进行回滚,会导致 T2、T3 接连着进行回滚;

问题分析

        可恢复调度无法避免脏读,所以会出现级联回滚的问题,解决级联回滚就需要避免脏读,而脏读产生的原因是读取未提交的数据。所以解决方案就是对事务的读写顺序进行限制,只允许读取已提交的数据;

解决方案

        无级联调度(Cascadeless Schedule)可以解决级联回滚的问题,其限制如下:

对于某个调度而言,如果它其中的任意一对事务 T1 和 T2 都满足:如果 T2 读取了先前由 T1 修改的数据项,则 T2 只能在 T1 提交后才能执行该读取操作;

       不满足上述要求的调度则被称为 级联调度(Cascading Schedule)。无级联调度有时也被称为 ACA(Avoiding Cascading Abort)调度 或  ACR(Avoiding Cascading Rollback)调度 。根据定义可以发现每个无级联调度都是可恢复调度;

        级联回滚不会影响数据的一致性,但会带来巨大的性能开销,应尽量避免。但在实现过程中,保证无级联调度也是有性能损耗的,会降低并发度,所以如果业务系统中级联回滚的情况很少发生,DBMS 也可以选择不实现这一特性;

脏写与严格调度

脏写的示例

(根据 《A Critique of ANSI SQL Isolation Levels》 论文的描述,脏写指的是:事务 T1 修改了一个数据项,而事务 T2 在 T1 提交或回滚前修改了该数据项,即“写未提交”

        无级联调度可能会出现脏写,比如:

T1 T2
Write(A)
Write(A)
Commit
Rollback
  1. 上述调度满足无级联调度的要求:T2 没有读取 T1 未提交的修改,T1 也没有读取 T2 未提交的修改;
  2. 但其中 T2 的 Write(A) 会导致脏写;

问题分析

        无级联调度无法避免脏写,导致调度难以恢复,而脏写产生的原因是修改未提交的数据。所以解决方案就是在无级联调度的基础上对调度进一步的限制,只允许修改已提交的数据;

        这里对脏写会带来的问题展开说明一下:

示例一:

T1 T2

数据项 D(初始值为 0)

(1) Write(D=1) 1
(2) Write(D=2) 2
(3) Commit 2
(4) Rollback 0

        事务 T1 执行 (4) 回滚时,此时如果恢复系统将 D 恢复到 T1 的修改操作 O1 之前的值 0,则会导致事务 T2 的修改操作 (2) 不生效,所以恢复系统必须得重做 T2 的写操作。这无疑增加了恢复的成本,因为恢复系统在恢复一个事务的同时,还得考虑到其他事务;

示例二:

T1 T2 T3

数据项 D(初始值为 0)

(1) Write(D=1) 1
(2) Write(D=2) 2
(3) Write(D=3) 3
(4) Commit 3
(5) Rollback ?
(6) Commit ?

        事务 T2 执行 (5) 进行回滚,此时无论恢复系统将 D 恢复到 T1 的修改操作 (1) 之前的值 0,还是 T2 的修改操作 (2) 之前的值 1,都会导致事务 T3 的修改操作 (3) 不生效。类似地,恢复系统必须得重做 T3 的写操作;

        所以脏写会导致调度难以恢复而不是无法恢复

解决方案

        严格调度(Strict Schedule)可以解决脏写的问题,其限制如下:

对于某个调度而言,如果它其中的任意一对事务 T1 和 T2 都满足:如果 T2 读取或修改了先前由 T1 修改的数据项,则 T2 只能在 T1 提交后才能执行该读取或修改操作;

        这种调度所具有的特性也被称为 严格性(Strictness)。根据定义可以发现每个严格调度都是无级联调度。

        注:部分文献中“Strict Schedule”一词的含义和此处有所不同,它们使用“严格调度”表示那些遵守 S2PL 协议的调度;

不可重复读和强严格调度

不可重复读的示例

        严格调度可能会出现不可重复读的问题,比如:

T1 T2
Read(A)
Write(A)
Commit
Read(A)
Commit


        上述调度满足严格调度的要求:T1 第二次读取的是 T2 已经提交的数据。但其中 T2 的 Write(A) 会导致 T1 不可重复读;

问题分析

        严格调度无法避免不可重复读,而不可重复读产生的原因是事务在结束前其已读数据再次被其他事务修改。所以解决方案就是在严格调度的基础上对调度进一步的限制,不允许其他事务再次修改该数据。

解决方案

        强严格调度(Rigorous Schedule)可以解决不可重复读的问题,其限制如下:

对于某个调度而言,如果它在满足严格调度要求的基础上还满足:如果 Ti 读取了某个数据项,则在 Ti 结束前,其他事务不可以修改该数据项;

         这种调度所具有的特性也被称为 强严格性(Rigorousness)。根据定义可以发现每个强严格调度都是严格调度;

小结

  1. 可恢复调度是通过限制提交顺序来解决不可恢复的问题,但并不能避免脏读(它已经解决了调度不可恢复的问题,但为了解决事务调度过程中的其他不良现象,从而诞生了无级联调度、严格调度以及强严格调度);
  2. 相比于可恢复调度,无级联调度通过 读已提交 避免了未提交事务之间写读冲突,即避免了脏读,也解决级联回滚的问题;
  3. 相比于无级联调度,严格调度通过 写已提交 避免了未提交事务之间 写写冲突,即避免了脏写 ;
  4. 相比于严格调度,强严格调度通过 在事务结束前禁止其已读数据被其他事务修改 ,避免了未提交事务之间的读写冲突,即避免了不可重复读的问题;

最后修改时间:2025-07-22 15:39:39
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论