1、第八章 事务管理,事物管理的基本概念1. 什么是事务1)定义:包含数据库操作的程序的一次执行称为一个数据库事务。2)用户定义事务的粒度(程序的规模)。3)例子:一段嵌入了数据操作语言的应用程序,上述程序的若干独立、并发的执行体,单个的数据库操作等 。典型事务,如银行转帐:帐户A 100元;帐户B + 100元。,2. 基本操作与状态,1)事务开始:开始执行。 2)事务读写:进行数据库操作。 3)事务结束:完成所有操作。 4)事务交付:完成所有操作,并保存所有结果。 5)事务撤消:执行途中出现异常,系统或用户撤消事务。,3. 系统赋予事务的特性,为了保证事务并发、有效、正确地执行,保证数据库的正
2、确性,系统必须赋予事务一些特性,而对一般的程序的执行,系统不一定赋予这些 特性。 1)原子性(Atomicity):事务的所有操作或全部完成,或全部不作。原子性在于保证正确性。如银行转帐,取款机。 2)持久性(Durability):保证已交付事务的结果不丢失,且与以后的故障无关。,3. 系统赋予事务的特性,为了保证事务并发、有效、正确地执行,保证数据库的正确性,系统必须赋予事务一些特性,而对一般的程序的执行,系统不一定赋予这些 特性。 3)隔离性(Isolation):任何事务不能访问到其他未交付事务的中间结果,防止多米诺效应。 4)一致性(Consistency),可串性(Serializ
3、ability):多个事务并发执行与它们的某一串行执行的结果等价。DBMS用并发控制机制维持可串性,用恢复机制维持原子性、持久性、隔离性。,例子:A、B、C三个帐户,初始资金分别为:200, 300,150,,有两个转帐事务:T1,从B转帐100到C,T2,从B转帐 50到A,并发控制性,尽管单个事务单独执行不破坏DB完整性,但它们并发执行时,如不加以适当控制,可能产生如下问题: 1.并发不当的问题:,3)丢失修改(Lost updates):,事务TA修改X为X;事务TB修改X为X”事务TA(TB)被撤消,造成事务TB(TA)的修改丢失;,例子:航空订票事务。动作1:找出一张未出售的座位票;
4、动作2:在其上登记已售标记、订票人;,两个订票事务TA、TB并发订票:TA动作1,找出一张未出售的座位票:S00120516F;TB动作1,找出一张未出售的座位票:S00120516F;TA动作2,在S00120516F票上登记已售标记、订票人张三;TB动作2,在S00120516F票上登记已售标记、订票人李四;,2. 可串行化调度,1)调度:对多个事务的操作的执行次序的一种安排。设有事务, T1: R1(x)W1(y)T2: R2(x)W2(x)T3: R3(y)W3(y),串行调度:T1T2T3S1:R1(x)W1(y) R2(x)W2(x) R3(y)W3(y),并发调度:S2:R2(x
5、)R1(x)W1(y)R3(y)W2(x)W3(y),串行调度,每一个事务的操作连续执行、各事务之间的操作没有任何重叠的调度称为串行调度。 例如: S2Ri(x)Wi(y)Ri(y)Rj(x)Wj(y)Rk(x)Wk(x) 串行执行从不会使数据库最后处于不一致状态,因此,所有的串行调度都被认为是正确的保持一致性。,串行调度,每一个事务的操作连续执行、各事务之间的操作没有任何重叠的调度称为串行调度。 例如: S2Ri(x)Wi(y)Ri(y)Rj(x)Wj(y)Rk(x)Wk(x) 串行执行从不会使数据库最后处于不一致状态,因此,所有的串行调度都被认为是正确的保持一致性。,2. 可串行化调度,并
6、发控制机构旨在尽可能提高事务并发度的同时,使得它们的并发执行保持数据库的一致性。 并发控制机构一般通过强制某些事务在执行它们的特定操作之前处于等待状态,或通过异常结束和重启事务来限制事务执行的可能操作序列,使该过程等价于串行调度。 为此,需要一些方法来判定并发执行的事务调度是否等价于一个串行调度。凡能够产生与某个串行调度相同结果的调度被称之为可串行调度。,3)冲突的操作对,在可串行化问题中,读写操作的次序非常重要。如果两个事务发出的两个操作都针对于同一数据项,只要其中有一个是写操作,则称这两个操作冲突。操作冲突可分为RW冲突、WR冲突以及WW冲突 如:, ,是冲突的。而, , xy=时不冲突。
7、,3)冲突的操作对,引起各种不一致的根本原因就是操作冲突。在两个调度Sa,Sb中,如果对于每对冲突的操作,都满足若在Sa中OiOj(如果Oi在调度Sa中先于Oj执行,则记为OiOj),则在Sb中也满足OiOj,即称Sa冲突等价于Sb。 这种类型的可串行化称之为冲突可串行化。 冲突可串行调度安排冲突操作的方式和某种串行调度一样。可以通过优先图(Precedence Graph)来判别一个调度是否冲突可串行化。,对于调度S,其优先图是一个有向图G=,其中节点集合N和有向边集合E构成如下: 为每一个事务创建一个节点; 如果事务Tj读取了事务Ti已写操作产生的数据项,创建一条有向边TiTj; 如果事务
8、Tj对事务Ti已读数据项执行写操作,创建有向边TiTj; 如果事务Tj对事务Ti已写操作产生的数据项执行写操作,创建有向边TiTj。 如果S的优先图中存在边TiTj,则表明在任何与S等价的串行调度S中,Ti必须在Tj前执行。如果优先图包含环,则说明调度不是冲突可串行的。,冲突可串行化是可串行化的充分非必要条件,更一般的可串行是计算可串行,即两个调度计算等价当且仅当同时满足以下两个条件: (1) 在两个调度中,每个读操作读取的数据项值,是由同一写操作产生的。 (2) 在两个调度中,对每个数据项的最后写操作相同。 当调度Sa计算等价于串行调度Sb时,称Sa是计算可串行的。若调度S是冲突可串行的,则
9、S是计算可串行的,反之不成立。,3. 并发控制机制,用户请求执行事务的时刻是随机的,系统如何在一种动态的环境下保证调度的可串性呢? 并发控制机构的任务就是调度事务的并发执行,使得这个调度等价于一个串行调度,在数据库中将这种方法称为串行化调度。对事务实施可串行化调度的并发控制机制主要有加锁技术、时间戳、多版本和乐观的并发控制技术。它们处理操作冲突的方法各不相同,3. 并发控制机制,1)封锁机制,是一种常用的并发控制机制。a. 二值锁(两态锁),每一数据项具有锁值LOCK(x):0(解锁)或 1(加锁)。 系统为事务访问数据x提供两个操作:lock_item(x) 和 unlock_item(x)
10、。,事务用锁规则,每个事务都必须遵循如下规则: 事务在读写数据项x之前,必须对其加锁lock_item(x)。 事务在完成了对数据项x的所有读写操作之后,必须对其解锁unlock_item(x) 。 事务在已经发出了一个lock_item(x)之后,未发出解锁 unlock_item(x)之前,不再对x加锁。 事务没有对数据项 x 加锁,就不能对 x 解锁unlock_item(x)。一个事务要访问被另一个事务加锁的数据项x时,必须等待它解锁,因而封锁机制就强制了事务操作的一种执行次序。,二值锁改进,考虑到事务执行的并发性,加锁应尽可能地减少因加锁对事务并发度的影响。 例如应该允许事务T1,T
11、2同时对数据项x进行读操作的并发执行 由于这两个读操作并非冲突的操作对,因此从提高系统性能角度来说应该允许它们并发执行。因此,可以将锁分为两类:共享锁(Shared Lock)和互斥锁(Exclusive Lock)。,b. 共享锁、互斥锁(读锁、写锁),共享锁:如果数据项被某事务用共享锁加锁,其它事务仍可用共享锁读它。,互斥锁:如果数据项被某事务用互斥锁加锁,其他事务欲 操作这一数据项,必须等待该事务释放此互斥锁。 锁LOCK(x)的三种状态:读锁、写锁和解锁。 锁的操作:read_lock(x)、write_lock(x)和unlock(x)。,c. 共享/互斥锁操作规则,事务必须遵循的规
12、则是: 事务在对数据项x进行读操作之前,必须发出 read_lock(x)或write_lock(x)请求。 事务在对数据项x进行写操作之前,必须发出write_lock(x)请求。 事务在完成了对数据项x的所有读写操作之后,必须发出unlock(x)请求。 事务在对x加锁(共享锁或互斥锁)后,不再对x进行任何形式的加锁。 事务没有对x加锁,就不能进行解锁unlock(x)。,read_lock(x),B: if LOCK(x) = 解锁then LOCK(x) = 读锁;no_of_reads(x) = 1;else if LOCK(x) = 读锁then no_of_reads(x) =n
13、o_of_reads(x) + 1;else 等待直到LOCK(x) = 解锁被唤醒执行;goto B;endif;endif.,write_lock(x),B: if LOCK(x) = 解锁then LOCK(x) = 写锁;else 等待直到LOCK(x) = 解锁被唤醒执行;goto B;endif.,unlock(x),if LOCK(x) = 写锁then LOCK(x) = 解锁;唤醒等待解锁的事务执行; else if LOCK(x) = 读锁then no_of_reads(x) := no_of_reads(x) 1;if no_of_reads(x) = 0then LO
14、CK(X) := 解锁;唤醒等待解锁的事务执行;endif;endif;endif.,改进之处,无论是使用二值锁还是使用共享锁和互斥锁,都不一定能够保证事务调度的串行性。 为了保证调度等价于一个串行调度,必须使用一个附加的协议来限制锁的操作时机。 两段锁协议正是这样的一个协议,它规定了在一个事务中所有的加锁操作必须出现在第一个解锁操作之前。,d. 两段封锁协议,两段锁协议规定在一个事务中所有的加锁操作必须出现在第一个解锁操作之前。即将一个事务分为两个阶段:扩展阶段:可以新加锁,但是不能释放锁;收缩阶段:可以释放锁,但是不能加新锁。可以证明,如果在一个调度中的所有事务均遵循两段锁协议,那么系统强
15、制执行的调度就是可串行的。,d.死锁和饿死,死锁:几个事务相互等待其他事务解锁而均不能正常结束的状态。,饿死:一个事务长时间等待其他事务解锁而不能正常执行的状态。,死锁检测与处理技术,死锁问题主要有以下几种处理方法: 1) 锁超时(Lock Timeout) 2) 死锁预防 3) 死锁检测与死锁恢复,死锁检测与处理技术,1) 锁超时(Lock Timeout): 为申请锁的事务的等待时间规定了一个上限,等待时间超过规定时间值,即在此期间内该事务没有获得申请的锁,则事务回滚并重启。,死锁检测与处理技术,2) 死锁预防:保证系统永远不进入死锁状态。 一种方法是通过对加锁请求进行排序或者要求事务在开
16、始执行前必须同时获得所有的锁来保证不会发生循环等待。 另外一种方法与死锁恢复接近,每当等待有可能导致死锁时,终止等待加锁行为,进行事务回滚。 第三种方法是抢占机制。在抢占机制中,当事务Ti所申请的锁已经被事务Tj所占有,可以抢占该锁,将授予Tj的锁强行授予Ti,并回滚事务Tj。为控制抢占,可以给每个事务赋予一个惟一的时间戳,系统仅用时间戳来决定事务应当等待还是回滚。,死锁检测与处理技术,3) 死锁检测与死锁恢复:当系统无法确保不会进入死锁状态时,一旦发生死锁,则应使用死锁检测与死锁恢复机制来解决。 (1) 死锁检测我们可以用一种称为等待图(Waitfor Graph)的有向图表示死锁。等待图中
17、节点表示事务,若存在从事务Ti到事务Tj的一条有向边,则表示事务Ti在等待Tj释放所需的数据项,当Tj释放加在该数据项上的锁时,则将这条边从等待图中删除。当且仅当等待图中存在环时,系统中存在死锁。为了能够及时检测到死锁的存在,系统必须维护等待图,并且周期性地判断等待图中是否存在有向环。,死锁检测与处理技术,(2) 死锁恢复死锁恢复通常采取回滚一个或多个事务的办法。死锁恢复的步骤一般为: 首先选择牺牲者:决定某一(些)事务将被回滚,使得等待图中不再有环,从而打破死锁。 回滚:将牺牲者回滚。那么将事务回滚到哪一步呢?简单地处理就是全部回滚,重新开始事务。还有一种方法是部分回滚,只要将事务回滚到可以
18、解除死锁处,而不是终止该事务。显然后者需要系统为维护事务的额外信息付出更大的代价。 避免饿死:当同一事务总是被选为牺牲者时,有可能发生饿死。为了避免事务被饿死,就必须保证事务被选为牺牲者的次数有限(且较少),2)基于时标的并发控制机制,基本思想:基于时标大小解决操作冲突,保证按时间顺序执行冲突操作。 a. 每个事务T开始执行时,系统给它打上时标t(一般 为当前时间)。 b. 系统中维持每个数据项x的最近读时标RTM(x)和最近写时标WTM(x)。 c. 事务所进行的每个读写操作均有时标属性t,当某事务T执行到某操作O时,比较事务T的时标t与操作对象x的读写时标,并按如下规则运作:,2)基于时标
19、的并发控制机制(续1), 当O是读操作时,如果 t WTM(x), 执行O, 修改x的读时标,使得:RTM(x)=max t, RTM(x) , 当O是写操作时,如果 t RTM(x)或 t WTM(x), 不能写,拒绝O,并将T的时标赋一新值,重新启动T。否则,执行O, 修改x的写时标,使得WTM(x)=t,例:,设有事务T1:R1(A)W1(A),时标为t1;事务T2:R2(A)W2(A),时标为t2;且有 t1 t2t3 t3 T1:W1(A),3)乐观的并发控制,不同于前面,在乐观并发控制中,对事务的执行过程不作任何检查,对数据库的修改也不立即进行,而是到事务结束时进行有效性检查。当事
20、务的执行不破坏可串性时,交付事务;否则将事务撤消,并回退,重新启动。该协议为三个阶段:1) 读阶段:事务直接从DB中读取数据项X的值,但修改维持在一副本中。2) 有效性阶段:在交付事务将操作结果写回DB之前,作有效性(可串性)检查。3) 写阶段:如有效性检查成功,将事务操作结果写回DB,否则放弃修改结果,重新启动事务。此种方法在事务间冲突操作较少时,效率较高,当冲突操作很多时,引起大量重启,降低效率。,乐观并发控制一般与时标技术结合使用,时标主要用于检查事务的有效性阶段。 假设当前事务为T,而已交付事务和正处于有效性阶段的事务组成一个集合G,那么事务T通过有效性检验,只要满足下列条件之一:1)
21、T开始读阶段在G中所有事务Ti完成写阶段之后;-Ti写阶段-T读阶段-2) G中所有事务Ti均在T完成写阶段之后才开始写阶段。并且Ti的写入集与T的读出集不相交。- T写阶段-Ti写阶段-3)T完成读阶段在G中所有事务Ti进入读阶段之前,并且Ti的写入集与T的读出集和写入集不相交。-T读阶段-Ti读阶段-,Oracle的并发控制,事务是并发控制的基本单位。 事务开始 事务结束(commit / rollback) DDL语句 单语句事务 set autocommit on (sql*plus) 自动加行锁 insert、update、delete 读提前加锁 select * For upda
22、te of 锁语句 LOCK 在事务中加的锁在事务结束时自动打开。,Oracle的并发控制,Oracle系统提供了五种类型的锁:S锁、X锁、RS锁、RX锁、SRX锁。 Oracle系统对数据的封锁是由系统自动 控制的。此外,还提供了显式命令LOCK TABLE,允许用户显式对数据对象加锁,显式锁优先。 Oracle 允许死锁,系统自动检测 和消除死锁。,Oracle如何解决死锁,Oracle系统在检测到一个死锁时,它会给引起死锁的其中一个事务发出一个错误信息,然后回滚该事务的当前语句。并告之用户应显式地回滚他的事务,而其他用户就会因获得资源而完成事务,死锁就被解开了。,数据库的恢复,数据库在运
23、行过程中,总是从一种完整状态转变为另一种完整状态。但是,由于种种原因,事务可能被撤消、重启,使得数据库停留在某一转变过程中间(不完整状态)。为了清除被撤消事务对数据库造成的影响,保证已交付事务的结果不丢失(达到新的完整状态),以及在系统故障修复后使数据库恢复到可用状态,需要使用恢复机制。,导致事务被撤消的原因1)系统失效、死机。2)事务或系统错误,如:零除,溢出。3)事务操作DB时,破坏数据库完整性。4)磁盘错误,坏块引起读写错。5)并发控制机制强迫事务撤消。,2.恢复的一般原则,1) 系统失效时损失应最小,重新启动系统时用户无须重新登记事务或数据,也不必从头开始执行原来的事务。2) 撤销或重
24、做的应尽可能是单个事务,不应造成在恢复时总是重新存储整个数据库或整个文件。3)恢复速度要快,因为恢复期间数据库中总会有部分数据用户不能使用(可利用周期性地整理恢复数据的方法缩短恢复消耗的时间)。4)应尽量较少恢复时的人工记录工作,即应尽可能自动地完成恢复工作,不要由用户保存恢复数据和决定恢复过程,这样既费时又容易出错。5)确保恢复数据的安全可靠。,2. 恢复机制的主要技术,DBMS应维持足够的信息,用以将数据库恢复到一致的状态。恢复的基本原理是数据冗余。1) 日志(log)日志内容一般包括:start_transaction, T:事务T开始执行的标记。write_item, T , x, o
25、ld_value, new_value:事务T将数据项x的值由old_value修改为new_value。read_item, T, x:事务T读取数据项x的值。commit_transaction, T:事务T完成所有操作,交付。,2)检查点(Check Point),为了允许部分回退与从断点处继续执行DBMS一般在某些时刻(称作检查点)将驻留在内存中的数据写回数据库并在日志中记录,避免系统停机等故障所造成的损失,也利于事务的恢复执行。系统检查点:系统周期性检查的时刻;事务检查点:用户在事务中设置的,要求系统记录事务的状态点。,“检查点记录”一般还包括:,活动事务表;每一活动事务在日志中的第
26、一条和最后一条记录的位置等。 DBMS在检查点处的工作: 暂停所有正在执行的事务; 将在内存中驻留的所有数据回写到数据库; 产生检查点记录,写到日志; 恢复所有被暂停的事务。系统一旦需要恢复数据库状态,就可以根据检查点记录的信息,从最新检查点处开始执行,而不需要从头开始执行那些被中断的事务。,3)像本,像本是整个数据库或某些部分在某一时刻的副本。像本的使用可以有效地解决由于磁盘故障引起的问题。建立像本就是把数据库中的数据转储到一个后援副本上,这一过程称为倒库或者转储(dump), 一般定期进行。静态转储动态转储 海量转储增量转储,3. 基于延迟修改的恢复技术,基于延迟修改的恢复技术的基本思想是
27、将事务中所有的写操作都延迟到终点完成。在事务执行过程中,对数据的修改动作保存在日志和事务空间中(以利于事务本身引用操作结果)。当事务到达终点时成功交付,系统将日志写回磁盘,并将修改数据写到数据库。如果事务在中途流产,由于事务对数据库的写操作实际上并没有进行,也就不会产生任何影响,因此就不需要恢复数据库内容。,延迟修改协议:,a.事务直到交付时才修改数据库内容; b. 事务只有当它的所有修改操作都记录到日志并且将日志写回磁盘后,才到达终点。假设一个系统中,并发控制使用两段锁和死锁防止机制(那么事务执行到达终点时才会释放所有对数据项所加的锁);恢复假设采用延迟修改协议并具有检查点机制,那幺恢复可以
28、采用如下算法:,从日志的最后一个记录开始,向前搜索记录信息,找到最近的一个检查点纪录; 构造两个事务列表:一个为已交付事务列表CTL,包含在最近检查点之后已经在日志中写入了commit_transaction,T的所有事务;另一个为未交付事务列表UTL,包含在日志中已经记录start_transaction,T但是没有commit_transaction,T的所有事务。 将列表CTL中所有事务的所有写操作按照其在日志中记载的顺序都Redo一次,原因是列表CTL中的写操作可能还没有对数据库产生影响。而UTL中的事务还没有对数据库产生影响,不必执行Undo操作。,按照上述算法,由于T1在检查点t1
29、处已经将操作结果回写至数据库,因此没有处理;但是T2和T3在t2之前已经交付,但恢复管理器并不清楚它们所做的更新是否都传送到了位于非易失存储上的数据库,因此必须重做;而T4和T5由于在故障点t2尚未提交,因此可以忽略它们在日志文件中的记录。,4. 基于立即修改的恢复技术,基于立即修改的恢复技术与基于延迟修改的恢复技术不同,在基于立即修改的恢复技术中,事务对数据库的修改不必等到交付就可以进行。但是在将数据回写到数据库之前必须在日志文件中记录操作内容,保证在系统故障时可以正确地恢复数据库,这种方法称为“先写日志”协议。,4. 基于立即修改的恢复技术,“先写日志”协议可以描述为: (1) 对于写操作
30、,只有对应的事务记录回写到磁盘上的日志文件后,才能修改物理数据库; (2) 只有事务的所有操作记录全部回写到磁盘上的日志文件后,它才可以交付。 由于允许数据的立即修改,恢复机制应该有能力通过消除事务的写操作影响来回滚事务。在这种恢复技术中,事务的中间结果可能会被其他事务引用,破坏了事务的隔离性,因此必须考虑到事务流产所引起的嵌套异常终止,在事务回滚处理时可能需要处理许多相关的事务。,4. 基于立即修改的恢复技术,下面的算法给出了一个具有检查点机制的立即修改恢复技术的简单步骤: 从日志文件的最后一个记录开始,向前搜索至最近的一个检查点,构造该点的活跃事务列表A; 构造在最近检查点之后交付的所有事
31、务列表TL; 使用Undo过程撤销不在列表TL中的所有事务的写操作; 穿过最近的一个检查点,使用Undo过程继续撤销ATL中的事务; 使用Redo过程重做列表TL中所有事务。,4. 基于立即修改的恢复技术,其中Undo过程为: 根据 T,O,x, old_value,new_value,将数据项x的值改为前像old_value。 如果有若干事务记录涉及到数据项x,按照它们在日志文件中出现的相反顺序进行。 Redo过程为: 根据 T,O,x, old_value,new_value,将数据项x的值改为后像new_value。 如果有若干事务记录涉及到数据项x,按照它们在日志文件中出现的顺序依次进行。,商用DBMS都有自己的恢复策略。 Oracle中提供了多种转储和装入方法 转储和装入的命令有Export、Import,SQL*LOADER等。 Oracle对日志文件提供REDO和回滚段(记录更新数据的前像)提高恢复效率。,Oracle的恢复技术,