数据库 __ 事务管理

数据库系统必须以一种能避免引入不一致性的方式来管理事务的并发执行。

事务概念

事务是访问并可能更新各种数据项的一个程序执行单元( unit ) 。
构成单一逻辑工作单元的操作集合称作事务( transaction ) 。
即使有故障(无论事务本身是否失败(例如,如果它除以零) , 或者操作系统崩溃,或者计算机本身停止运行),数据库系统必须保证事务的正确执行——要么执行整个事务,要么属于该事务的操作一个也不执行。

构成:

事务用形如begin transaction 和end transaction 语句(或函数调用)来界定。
事务由begin transaction 与( end transaction 之间执行的全体操作组成。

四个特性

事物特性(ACID)

原子性(Atomicity)

原子性(Atomicity):事务中包含的所有操作要么全做,要么全不做。

原子性由恢复系统实现。
保证原子性的基本思路如下:
对于事务要执行写操作的数据项,数据库系统在磁盘上记录其旧值。这个信息记录在一个称为日志的文件中。如果事务没能完成它的执行,数据库系统从日志中恢复旧值,使得看上去事务从未执行过。

一致性(Consistency)

一致性(Consistency): 事务的隔离执行必须保证数据库的一致性。

事务开始前,数据库处于一致性的状态;事务结束后,数据库必须仍处于一致性状态;
事务的执行过程中可以暂时的不一致。
数据库的一致性状态由用户来负责,由并发控制系统实现

隔离性(Isolation)

隔离性(Isolation) :系统必须保证事务不受其它并发执行事务的影响。也可以理解为对任何一对事务T1,T2,在T1看来,T2要么在T1开始之前已经结束,要么在T1完成之后再开始执行。

为什么需要隔离性?
即使每个事务都能确保一致性和原子性,它们的操作会以人们所不希望的某种方式交叉执行,这也会导致不一致的状态。
例如,在A 至B 转账事务执行过程中, 当A 中总金额已减去转账额并已写回A, 而B 中总金额加上转账额后还未写回B 时,数据库暂时是不一致的。如果另一个并发运行的事务在这个中间时刻读取A 和B 的值并计算A +B, 它将会得到不一致的值。
更进一步,如果第二个事务基千它读取的不一致值对A 和B 进行更新,即使两个事务都完成后,数据库仍可能处于不一致状态。
解决方法:
一种避免事务并发执行而产生问题的途径是串行地执行事务 ———— 一个接一个地执行。
然而,容易想到事务并发执行能显著地改善性能。因此人们提出了许多其他的解决方法,它们允许多个事务并发地执行。
后面会讨论事务并发地执行所引起的问题。
事务的隔离性确保事务并发执行后的系统状态与这些事务以某种次序一个接一个地执行后的状态是等价的。
隔离性通过并发控制系统实现。

持久性(Durability)

持久性(Durability):一个事务一旦提交之后,它对数据库的影响必须是永久的,系统发生故障不能改变事务的持久性。

存储器分为:

  1. 易失性存储器(高速缓冲区)
    速度极快
  2. 非易失性存储器(磁盘和闪存等)
    速度慢,随机访问速度更慢
  3. 稳定存储器(通过备份实现)
    (理论上保证数据永远不会丢失,不可能实现,可以采用备份的方式使丢失的可能性微乎其微)。
    蜗牛速度。

因此,为了一个事务能够拥有持久性。就要保证当事务完成后,事务的执行结果在稳定存储器上。
可以确保以下两条中的任何一条来达到待久性:

  1. 事务做的更新在事务结束前已经写入磁盘。
  2. 有关事务已执行的更新信息己写到磁盘上,并且此类信息必须充分,能让数据库在系统出现故障后重新启动时重新构造更新。

持久性通过恢复系统实现。

事务原子性和持久性

正如我们先前所注意到的,事务并非总能成功地执行完成。这种事务称为中止(aborted ) 了。
我们如果要确保原子性,中止事务必须对数据库的状态不造成影响。
因此,中止事务对数据库所做过的任何改变必须撤销。
一旦中止事务造成的变更被撤销,我们就说事务已回滚(rolled back)
恢复机制负责管理事务中止。
典型的方法是维护一个日志(log) 。每个事务对数据库的修改都首先会记录到日志中。
我们记录执行修改的事务标识符、修改的数据项标识符以及数据项的旧值(修改前的)和新值(修改后的),然后数据库才会修改。
维护日志提供了重做修改以保证原子性和持久性的可能,以及撤销修改以保证在事务执行发生故障时的原子性的可能。

成功完成执行的事务称为已提交(committed)。 一个对数据库进行过更新的已提交事务使数据库进人一个新的一致状态,即使出现系统故障,这个状态也必须保持。

一旦事务已提交,我们不能通过中止它来撤销其造成的影响。
撤销已提交事务所造成影响的唯一方法是执行一个补偿事务
例如,如果一个事务给一个账户加上了$ 20 , 其补偿事务应当从该账户减去$20 。
然而,我们不总是能够创建这样的补偿事务。
因此,书写和执行一个补偿事务的责任就留给了用户,而不是通过数据库系统来处理。

为了更准确地定义一个事务成功完成的含义。为此建立了一个简单的抽象事务模型。事务必须处于以下状态之一。

  1. 活动的(active) :初始状态,事务执行时处于这个状态。
  2. 部分提交的( partially committed) :最后一条语句执行后。
  3. 失败的(failed) :发现正常的执行不能继续后。
  4. 中止的(aborted) :事务回滚并且数据库已恢复到事务开始执行前的状态后。
  5. 提交的(committed) :成功完成后。

事务相应的状态图如图所示。

image

只有在事务已进入提交状态后,我们才说事务已提交。仅当事务已进入中止状态,我们才说事务已中止。
如果事务是提交的或中止的,它称为已经结束。

  • 事务从活动状态开始。

  • 当事务完成它的最后一条语句后就进入了部分提交状态。
    此刻,事务已经完成执行,但由于实际输出可能仍临时驻留在主存中,因此一个硬件故障可能阻止其成功完成,因此事务仍有可能不得不中止。

  • 接着数据库系统往磁盘上写入足够的信息,确保即使出现故障时事务所做的更新也能在系统重启后重新创建。 当最后一条这样的信息写完后,事务就进入提交状态。(我们假设故障不会引起磁盘上的数据丢失。)
    注意此时不是保证事务的结果完全写入到磁盘,而是确保出现故障也能恢复的信息完全写入磁盘(也就是日志文件)。

  • 系统判定事务不能继续正常执行后(例如,由于硬件或逻辑错误)、事务就进入失败状态。这种事
    务必须回滚。这样,事务就进入中止状态。此刻,系统有两种选择。

    • 重启(restart ) 事务: 但仅当引起事务中止的是硬件错误或不是由事务的内部逻辑所产生的软件错误时。
      重启的事务被看成是一个新事务。
    • 杀死( kill) 事务:这样做通常是由于事务的内部逻辑造成的错误,只有重写应用程序才能改正,或者由输入错误,或所需数据在数据库中没有找到。
  • 在处理可见的外部写,比如写到用户屏幕,或者发送电子邮件时:由于写的结果可能已经在数据库系统之外看到,因此一旦发生这种写操作,就不能再抹去。
    大多数系统只允许这种写操作在事务进入提交状态后发生。实现这种模式的一种方法是在非易失性存储设备中临时写下与外部写相关的所有数据,然后在事务进入提交状态后再执行真正的写操作。
    如果在事务已进入提交状态而外部写操作尚未完成之时,系统出现了故障,数据库系统就可以在重启后(用存储在非易失性设备中的数据)执行外部写操作。

事务隔离性

事务处理系统通常允许多个事务并发地执行,而允许多个事务并发更新数据,会引起许多数据一致性的复杂问题。
在存在事务并发执行的情况下保证一致性需进行额外工作;
如果我们强制事务串行地执行将简单得多:一次执行一个事务,每个事务仅当前一事务执行完后
才开始。
然而,有两条很好的理由允许并发

  1. 提高吞吐量和资源利用率。
    一个事务由多个步骤组成。一些涉及I/0 活动;还有一些涉及CPU活动。在计算机系统中CPU 与磁盘之间可以并行运作,不同磁盘之间可以并行运作。
    因此, 利用I/O活动与CPU处理并行进行,可以显著提高的系统的吞吐量(即给定时间内执行的事务数增加)。相应地,处理器与磁盘利用率也会提高。
  2. 减少等待时间。
    系统中可能运行着各种各样的事务,一些较短, 一些较长。如果事务串行地执行,短事务可能得等待它前面的长事务完成,这可能导致难以预测的延迟。
    如果各事务针对数据库的不同部分进行操作,让它们并发地执行会更好,它们之间可以共享CPU周期与磁盘存取。
    并发执行可以减少执行事务时不可预测的延迟。此外, 也可减少平均响应时间(即一个事务从提交到完成所需的平均时间)。

调度

当多个事务并发地执行时, 可能违背隔离性。数据库系统必须控制事务之间的交互,以防止它们破坏数据库的一致性,系统通过称为并发控制机制来保证这一点。
我们可以通过限制事务的并发执行,来达到这一点,为了描述事务的执行,引入调度的概念。

事务的执行顺序称为一个调度(schedule),表示事务的指令在系统中执行的时间顺序。
(显然,一组事务的一个调度必须包含这一组事务的全部指令,并且必须保持指令在各个事务中出现的顺序。)

如下图:
事务1:从账户A 过户$50 到账户B.
事务2: 从账户A 将存款余额的10%过户到账户B.
image
上图这两个调度是串行的调度。每个串行调度由来自各事务的指令序列组成,其中属于同一事务的指令在调度中紧挨在一起。
易得有n个事务的事务组,共有n! 个不同的有效串行调度。

当数据库系统并发地执行多个事务时,相应的凋度不必是串行的。例如下面两调度都是有可能的。
image
image

一种可能的调度如图1 4-4 所示,当它执行完成后,我们到达的状态与执行的串行调度一样,A+B 之和保持不变。
一种可能的调度如图1 4-5 所示,该调度执行后,两个账户之和会多出$50,两个事务执行后A+B之和未能保持不变。

因此为了保证所执行的调度都能使数据库处于一致状态,数据库系统的任务系统设计了并发控制部件来保证隔离性。

在并发执行中,通过保证所执行的任何调度的效果都与没有并发执行的调度效果一样,我们可以确保数据库的一致性。也就是说,调度应该在某种意义上等价于一个串行调度。这种调度称为可串行化调度

可串行化

为了方便描述,我们先只考虑两种操作:read和write

我们考虑一个调度S, 其中含有分别属于I 与J 的两条连续指令I与J:
如果l 与J 引用不同的数据项,则交换I 与J 不会影响调度中任何指令的结果。
如果引用相同的数据项,由于我们只处理read 与write 指令,因此需考虑以下4种情形:

  1. I = read (Q), J = read ( Q) 。
    I 与J 的次序无关紧要,因为不论其次序如何读取的Q值总是相同的。
  2. I= read(Q) , J = write ( Q ) 。
    I 与J 的次序是重要的,不难想到原因。
  3. l = write(Q), J = read (Q) 。
    I 与j 的次序是重要的,不难想到原因。
  4. I= write(Q). J = write ( Q) 。
    由于两条指令均为write 指令,因此指令的顺序对I、J没有什么影响。
    然而,可能调度S 的下一条read ( Q ) 指令读取的值将受到影响,因为数据库里只保留了两条write指令中后一条的结果。
    也可能如果在调度S 的指令I 与J 之后没有其他的write(Q) 指令,则I、J的顺序直接影响调度S 产生的数据库状态中Q 的最终值。

因此,只有在I 与J 全为read 指令时,两条指令的执行顺序才是无关紧要的。
因此引出一个新概念:
冲突: 当两条指令是不同事务在相同数据项上的操作,并且其中至少有一个是write指令时,则称这两条指令是冲突的。

容易得知,若l 与J 是属于不同事务的指令且不冲突,则可以交换I 与J的顺序得到一个新的调度S' 。且S与S'等价。

我们称:如果调度S可以经过一系列非冲突指令交换转换成调度S',则称调度S与S'是冲突等价

由冲突等价的概念引出了冲突可串行化的概念:
若一个调度S 与一个串行调度冲突等价,则称调度S是冲突可串行化

冲突可串行化判定: 优先图

串行化顺序可通过拓扑排序得到。

事务隔离性和原子性

至此,我们在隐含地假定无事务故障的前提下学习了调度。
不论什么原因,如果事务T失败了,我们必须撤销该事务的影响以确保其原子性。
在允许并发执行的系统中,原子性要求依赖于I的任何事务J( 即J读取了I写的数据)也中止。
为确保这一点,我们需要对系统所允许的调度类型做一些限制。

可恢复调度

考虑图1 4-14 所示的部分调度9, 其中事务只执行一条指令: read ( A ) 。我们称之为部分调度
image
image

调度9 是不可恢复调度的一个例子。

因此 一个可恢复调度应满足:对于每对事务I、J, 如果J读取了之前由I所写的数据项,则I先于J提交。

隔离性级别的实现

有多种方法可以保障事务的隔离性。
最常用的方式就是通过锁。

1. 锁

锁就是指:只有获得相应的锁后,才能执行相应的操作。

我们将锁分为两类:

  1. 共享锁:用于事务数据项。
    许多事务可以同时持有一个数据项上的共享锁。
  2. 排他锁:用于事务数据项。
    只有当其他事务在一个数据项上不持有任何锁( 无论共享锁或排他锁)时,一个事务才允许待有该数据项上的排他锁。

两段锁协议: 将事务分为两个阶段,一个阶段只获得锁但不释放锁,第二个阶段只释放锁但是不获得锁。

两种锁模式以及两阶段封锁协议在保证可串行化的前提下允许数据的并发读。

2. 时间戳

时间戳方法:

  1. 每个事务分配一个时间戳,通常是当它开始的时候。

  2. 对于每个数据项,系统维护两个时间戳。
    数据项的读时间戳:记录读该数据项的事务的最大(即最近的)时间戳。
    数据项的写时间戳:记录写入该数据项当前值的事务的时间戳。

  3. 时间戳用来确保在访问冲突情况下,事务按照事务时间戳的顺序来访问数据项。

  4. 当不可能访问时,违例事务将会中止,并且分配一个新的时间戳重新开始。

posted @ 2022-06-11 22:07  kingwzun  阅读(141)  评论(0编辑  收藏  举报