事务处理技术事务是一系列的数据库操作,是数据库应用程序的基本逻辑单元。(一个存取或更改数据库的程序的运行)事务处理技术1、并发控制技术:用来控制多个事务的并行运行,避免它们之间的相互干扰,保证每个事务都产生正确的结果。2、数据库恢复技术:用来进行系统失败后的恢复处理,确保数据库能够恢复到正确的状态。事务的概念背景知识1、古老而典型的例子提起事务,就会用到银行中两个账户之间转帐的例子,即从账户A转X元到帐户B,它同时涉及到两个不同帐户的读写操作。2、事务中涉及数据库访问的基本操作⑴read(X):从数据库传送数据项X到执行read操作的事务的一个局部缓冲区中;⑵write(X):从执行write事务的局部缓冲区中把数据项X传回数据库。3、事务之间的相互影响数据库系统中同时可能有很多事务要执行,这些事务要么互不相干,要么要访问相同的数据项。对于那些要访问相同数据项的事务之间的相互影响要特别处理。Ti:假设A的初始值为2000,Tjread(A)B的初始值为3000。read(A)A:=A-500read(B)write(A)X:=A+Bread(B)write(X)B:=B+500write(B)事务之间的相互影响如图所示。事务Ti是从A帐户转500元钱到B帐户,事务Tj是计算帐户A和账户B的和。两个事务同时在系统中执行,那么事务Tj的read(A)操作可能在事务Ti的write(A)之前或之后执行;同理,事务Tj的read(B)操作也可能在事务Ti的write(B)之前或之后执行。如果事务Tj的read(A)操作在事务Ti的write(A)之前执行,而事务Tj的read(B)操作却在事务Ti的write(B)之后执行,那么事务Tj的计算结果是5500,而不是想象中的5000,凭空就多了500元钱。事务的状态一个事务必须处于如下状态之一:1.活动状态2.部分提交状态3.失败状态4.异常结束状态5.提交状态我们可以在事务中执行如下的操作来实现事务状态的转换:(1)BEGIN-TRANSACTION开始运行事务,使事务进入活动状态(2)END-TRANSACTION说明事务中的所有读写操作都已完成,使事务进入部分提交状态,把事务的所有操作对数据库的影响存入数据库(3)COMMIT-TRANSACTION标志事务已经成功地完成,事务进入提交状态,结束事务的运行(4)ABOUT-TRANSACTION标志事务进入失败状态,系统消除事务中所有操作对数据库和其他事务的影响,结束事务的运行除了上述操作外,有些数据库恢复技术还要求如下操作:(1)UNDO消除事务中指定数据操作对数据库的影响(2)REDO重新执行事务中指定数据库操作,保证该操作对数据库的影响能够安全地存入数据库事务的特性需要由数据库管理系统的并发控制和数据库恢复机制来保证。原子性事务是数据库系统运行的原子程序单元。每个事务的所有操作要么被全部成功地执行,要么一个也不被执行。数据库正确保持性一个事务的正确执行必须把数据库从一个正确状态转换为另一个正确状态。操作结果永久保持性如果一个事务使数据库发生了改变,而且该事务已经进入提交状态,则这些改变将不会因以后的失败而丢失。独立性一个事务在进入提交状态之前,它对数据库的更新不可由其他事务读取。这个性质避免了临时值问题,也避免了嵌套回滚处理问题。一般地,不同的并发控制和数据库恢复方法要求不同级别的独立性。可串行性并发运行的多个事务的运行效果与这些事务按某种次序顺序运行的效要相同。可串行性是各种并发控制方法所要求的关键性质。保证事务的原子性是数据库恢复机制的责任。数据库正确保持性简单地说就是数据库中数据的完整性,包括它们的正确性。对于图中的事务Ti来说,一致性要求就是事务的执行不改变账户A和账户B的和。否则的话事务就会创造或销毁钱!单个事务的一致性是由对该事务进行编码的应用程序员的责任,但是在某些情况下利用DBMS中完整性约束(如触发器)的自动检查功能有助于一致性的维护。Ti:Ti:read(A)read(A)A:=A-500A:=A-500write(A)write(A)read(B)read(B)B:=B+500B:=B+500write(B)write(B)图1事务Ti图2执行过程中发生故障的事务Ti原子性如果事务没有原子性的保证,那么在发生系统故障的情况下,数据库就有可能处于不一致状态。如图2所示,如果故障发生在write(A)和read(B)之间,则将有可能造成账户A的余额已经减去500元钱,而账户B的余额却没有改变,凭空就少了500元钱。值得注意的是,即使没有故障发生,系统在某一时刻也会处于不一致状态。原子性的要求就是这种不一致状态除了在事务执行当中出现外,在其他任何时刻都是不可见的。保证原子性是DBMS的责任:即事务管理器和恢复管理器的责任。操作结果永久保持性持久性的含义是说:一旦事务成功执行之后,它对数据库的更新是永久的。可以用以下两种方式中的任何一种来达到持久性的目的:⑴以牺牲应用系统的性能为代价:要求事务对数据库系统所做的更新在事务结束前已经写入磁盘;⑵以多占用磁盘空间为代价:要求事务已经执行的和以写到磁盘的、对数据库进行更新的信息是充分的(例如,数据库日志的信息就足够的多),使得DBMS在系统出现故障后重新启动系统时,能够(根据日志)重新构造更新。保证持久性也是DBMS的责任:即恢复管理器的责任。独立性⑴事情的起因如图所示,即使每个事务都能保持一致性和原子性,但如果几个事务并发执行,且访问相同的数据项,则它们的操作会以人们所不希望的某种方式交叉执行,结果导致不一致的状态!Ti:访问相同数据项ATjread(A)和B的两个事务的read(A)A:=A-5并发执行read(B)write(A)X:=A+Bread(B)write(X)B:=B+500write(B)访问相同数据项的两个事务并发执行⑵解决办法如果几个事务要访问相同的数据项,为了保证数据库的一致性,可以让这几个事务:①串行执行:即一个接着一个地执行事务;②并发执行:即同时执行多个事务,但用并发控制机制来解决不同事务间的相互影响。⑶独立性的保证事务的隔离性能够确保事务并发执行后的系统状态与这些事务安某种次序串行执行后的状态是等价的。保证独立性也是DBMS的责任:即并发控制管理器的责任。事务调度与可串行性事务的调度定义12.3.1:N个事务的一个调度S是N个事务的所有操作的一个序列,表示这些操作的执行顺序,并且满足对于N个事务中的每个事务T,如果操作i在T中先于操作j执行,则在S中操作i也必须先于操作j执行。多个事务的调度保持每个事务的操作在该事务中的顺序不变。但是,不同事务的操作可以交叉执行。一个事务的所有操作都执行完后才执行完后才执行另一个事务的所有操作。我们称这样的调度为串行调度,表示事务的串行运行。称其他类型的调度为并行调度。调度的可串行性对于N个事务来说,有N!个串行调度。由于N个事务可以有很多种并行调度,N个事务的调度个数远大于N!。调度的可串行性N个事务S是可串行的,如果S等价于一个串行调度。串行调度一定产生正确的运行结果,而并行调度可能产生不正确的事务运行结果。一个并行调度等价于一个串行调度意味着并行调度是正确的。第12章并发控制技术并发操作:不同用户使用同一数据并发控制:对并发操作加以正确调度,给数据库以回答并发控制的重要性事务T1取消航班A1上已经预订的N个座位,并为航班A2增加N个预定座位;事务T2为航班A1增加M个座位:T1:READ(X);T2:READ(X);X:=X-N;X:=X+M;WRITE(X);WRITE(X);READ(Y);Y:=Y+N;WRITE(Y);1、数据更新丢失问题(X=80,M=4,N=5)T1T2READ(X);X:=X-N;READ(X);X:=X+M;WRITE(X);READ(Y);WRITE(X);84Y:=Y+N;WRITE(Y);792、临时值问题T1T2READ(X);X:=X-N;WRITE(X);READ(X);X:=X+M;WRITE(X);READ(Y);T1失败,X的值必须恢复为原值,但T2已经使用了X的不正确的临时值3、错误聚集计算问题T1T3SUM:=0;READ(A);SUM:=SUM+A;READ(X);X:=X-N;WRITE(X);READ(X);SUM:=SUM+X;READ(Y);SUM:=SUM+Y;READ(Y);Y:=Y+N;WRITE(Y);基于锁的并发控制协议一个保证可串行性的方法是在互斥的方式下存取数据项,即当一个事务存取一个数据项时,不允许其他事务修改这个数据项锁的概念锁是数据项上的并发控制标志(1)共享锁:如果事务T得到了数据项Q上的共享锁,则T可以读这个数据项,但不能写这个数据项。共享锁表示为S.(2)互斥锁:如果事务T得到了数据项Q上的互斥锁,则T既可以读这个数据项,也可以写这个数据项。互斥锁表示为X.每个事务在存取一个数据项之前必须获得这个数据项上的锁。一个事务需要获得的锁的类型依赖于它将在数据项上执行什么样的操作。给定一个各种类型锁的集合,可以如下定义这个锁集合上的相容关系。令A和B表示任意类型的锁。设事务Ti在数据项Q上要求一个A型锁,事务Tj(Ti≠Tj)已经在Q上有一个B型锁。如果事务Ti能够获得Q上的A型锁,则说A型锁和B型锁是相容。锁相容矩阵SXStruefalseXfalsefalse申请数据项Q上的共享锁LOCK-S(Q)申请数据项Q上的互斥锁LOCK-X(Q)释放数据项Q上的锁UNLOCK(Q)银行数据库系统的例子设A和B是两个账号。定义两个事务T7和T8。T7从账号B向账号A转50元,T8显示账号A和B的总金额。(设A和B的值分别是100和200元)。T7和T8定义如下:T7:LOCK-X(B);T8:LOCK-S(A);READ(B);READ(A);B:=B-50;UNLOCK(A);WRITE(B);LOCK-S(B);UNLOCK(B);READ(B);LOCK-X(A);UNLOCK(B);READ(A);DISPLAY(A+B);A:=A+50;WRITE(A);串行执行T7,T8或T8,T7UNLOCK(A);T8显示300元并发执行T7:LOCK-X(B);T8:READ(B);B:=B-50;WRITE(B);UNLOCK(B);LOCK-S(A);READ(A);UNLOCK(A);LOCK-S(B);READ(B);UNLOCK(B);DISPLAY(A+B);LOCK-X(A);READ(A);A:=A+50;WRITE(A);UNLOCK(A);T8显示250元,T8看到的是一个不一致的数据库状态.修改T7和T8得到,T9和T10T9:LOCK-X(B);T10:LOCK-S(A);READ(B);READ(A);B:=B-50;READ(B);WRITE(B);LOCK-X(A);READ(A);UNLOCK(A);A:=A+50;UNLOCK(B);WRITE(A);DISPLAY(A+B);UNLOCK(B);UNLOCK(A);一个处于死锁状态的调度T9:LOCK-X(B);T10:READ(B);B:=B-50;WRITE(B);LOCK-S(A);READ(A);LOCK-S(B);LOCK-X(A);应该谨慎地使用锁.如果为了获得最大的并发性而尽早地释放数据项的锁,可能导致不一致的数据库状态.如果在申请其它锁之前不尽量地释放已拥有的锁,则可能导致死锁.要求系统中每个事务在加锁或释放锁时都必须遵循一组规则.这组规则称为锁协议.它规定了事务对每个数据项加锁和释放锁的时机.两阶段锁协议两阶段锁协议要求每个事务分两个阶段进行数据项的加锁和解锁阶段1加锁阶段.事务可以申请获得任何数据向上的任何类型的锁,但是不能释放任何锁.阶段2解锁阶段.事务可以释放任何数据向上的任何类型的锁,但是不能再申请任何