协调多用户数据库系统中事务的同时执行被称为并发控制。并发控制的目的是确保多用户数据库环境中事务的可序列化性。为了实现此目标,大多数并发控制技术都旨在保留并发执行的事务的隔离属性。并发控制很重要,因为在共享数据库上同时执行事务会产生一些数据完整性和一致性问题。三个主要问题是更新丢失,数据未提交以及检索不一致。
1. 更新丢失(Lost Updates)
当两个并发事务T1和T2正在更新同一数据元素并且其中一个更新丢失(被另一个事务覆盖)时,会发生丢失更新的问题。要查看丢失的更新的图示,请检查一个简单的PRODUCT表。该表的属性之一是手头上的产品数量(PROD_ QOH)。假定您有一个当前PROD_QOH值为35的产品。还要假设发生两个并发事务T1和T2,并更新PRODUCT表中某些项目的PROD_QOH值。交易记录在表10.2中。
2. 未提交数据(Uncommitted Data)
当同时执行两个事务T1和T2,并且在第二个事务(T2)已经访问了未提交的数据之后第一个事务(T1)被回滚时,就会发生未提交数据的现象,从而违反了事务的隔离性。为了说明这种可能性,请使用丢失更新讨论中描述的相同事务。 T1有两个原子部分,其中之一是库存更新。另一个可能的部分是发票总额的更新(未显示)。在更新发票总额时,T1由于错误而被迫回滚;它会一直回滚,也撤消库存更新。这次T1事务回滚以消除增加的100个单位。 (请参阅表10.5。)由于T2从原来的35个单位中减去了30个,因此正确答案应为5。
3. 不一致检索(Inconsistent retrievals)
当事务在一个或多个其他事务处理完此类数据之前和之后访问数据时,就会发生不一致的检索。例如,如果事务T1在一组数据上计算了某个汇总(汇总)函数,而另一个事务(T2)正在更新同一数据,则会出现不一致的检索。问题在于事务可能会在更改之前读取某些数据,而在更改之后读取其他数据,从而产生不一致的结果。
为了说明此问题,假定满足以下条件:
1. T1计算PRODUCT表中存储的现有产品总数。
2.同时,T2更新PRODUCT表中两个产品的现有数量(PROD_QOH)。
这两个事务显示在表10.8中。
T1计算所有商品的总库存量(PROD_QOH),而T2表示输入错误的更正:用户向产品1558-QW1的PROD_QOH添加了10个单位,但打算向产品1546-QQ2的PROD_QOH添加了10个单位。为解决此问题,用户向产品1546-QQ2的PROD_QOH添加10,并从产品1558-QW1的PROD_QOH减去10。 (请参见表10.8中的两个UPDATE语句。)表10.9反映了初始和最终PROD_QOH值。 (仅在PRODUCT表中显示了几个PROD_CODE值。为说明这一点,在这几个产品中显示了PROD_QOH值的总和。)
尽管表10.9中显示的最终结果在调整后是正确的,但表10.10证明了在事务执行期间可能出现不一致的检索,从而使T1的执行结果不正确。表10.10中显示的“之后”总和反映了在完成WRITE语句之后读取了产品1546-QQ2的25值。因此,“之后”总数为40 + 25 =65。“之前”总数反映了在下一个WRITE语句完成之前已读取产品1558-QW1的23的值,以反映对13的更正更新。因此, “之前”总计为65 + 23 = 88。
计算得出的102答案显然是错误的,因为从表10.9知道正确答案是92。除非DBMS进行并发控制,否则多用户数据库环境会在信息系统内造成严重破坏。
4. 调度器(The Scheduler)
您现在知道执行两个或多个并发事务时会出现严重问题。您还知道数据库事务涉及一系列数据库I / O操作,这些操作将数据库从一种一致的状态转移到另一种一致的状态。最后,您知道只能在执行事务之前和之后才能确保数据库的一致性。如果事务更新了多个表和行,那么在事务执行期间,数据库总是会经历不可避免的临时不一致状态。 (如果事务仅包含一个更新,则不会存在暂时性的不一致。)之所以存在暂时性的不一致,是因为一台计算机一个接一个地串行执行操作。在此串行过程中,事务的隔离属性会阻止它们访问其他事务尚未释放的数据。今天,考虑到可以同时执行多条指令的多核处理器的使用,这一考虑就变得更加重要。如果两个事务同时执行并且正在访问相同的数据,将会发生什么?
在前面的示例中,事务内的操作以任意顺序执行。只要T1和T2这两个事务访问无关的数据,就不会发生冲突,并且执行顺序与最终结果无关。但是,如果事务处理相关数据或相同数据,则事务组件之间可能会发生冲突,并且选择一个执行顺序而不是另一个执行顺序可能会带来一些不良后果。那么,如何确定正确的订单,谁来确定该订单?幸运的是,DBMS通过使用内置的调度程序来处理棘手的分配。
调度程序是一个特殊的DBMS进程,它建立并发事务中执行操作的顺序。调度程序交错执行数据库操作,以确保可串行性和事务隔离。为了确定合适的顺序,调度程序将基于并发控制算法(例如锁定或时间戳方法)来执行其操作,这将在下一部分中进行说明。但是,重要的是要了解并非所有事务都可以序列化。 DBMS确定哪些事务可序列化,然后继续进行事务操作的执行。通常,不可序列化的事务由DBMS以先到先得的方式执行。调度程序的主要工作是为事务的操作创建可序列化的调度,其中事务的交错执行(T1,T2,T3等)产生的结果与按串行顺序执行事务的结果相同(一个接一个) )。
5. 并发控制的锁定方法(Concurrency Control with Locking Methods)
锁定方法是并发控制中最常用的技术之一,因为它们有助于隔离在并行执行的事务中使用的数据项。锁可以保证将数据项专用于当前事务。换句话说,事务T2无法访问事务T1当前正在使用的数据项。事务在访问数据之前先获得一个锁;事务完成后,将释放(解锁)锁定,以便另一个事务可以锁定数据项以供其专用。这一系列锁定操作假定并发事务可能试图同时操纵同一数据项。基于事务之间可能发生冲突的假设使用锁通常被称为悲观锁。
回顾第10-1a和10-1b节,在交易期间不能保证数据的一致性;执行多个更新时,数据库可能处于暂时不一致的状态。因此,需要使用锁来防止其他事务读取不一致的数据。
大多数多用户DBMS自动启动并强制执行锁定过程。所有锁信息由锁管理器处理,锁管理器负责分配和管理事务使用的锁。
5.1 锁粒度(Lock granularity)
锁粒度指示锁的使用级别。锁定可以在以下级别进行:数据库,表,页面,行甚至字段(属性)。
数据库级别在数据库级别的锁定中,整个数据库都被锁定,从而防止了事务T2在执行事务T1时使用数据库中的任何表。此锁定级别对于批处理非常有用,但不适用于多用户DBMS。您可以想象,如果成千上万的事务必须等待上一个事务完成,然后下一个事务才能保留整个数据库,那么数据访问将是多么糟糕。图10.3说明了数据库级别的锁定;因此,事务T1和T2即使使用不同的表也无法同时访问同一数据库。
表级(Table Level):表级锁中,整个表都被锁定,从而防止事务T2在使用表时由事务T2访问任何行。如果事务需要访问多个表,则每个表都可能被锁定。但是,两个事务可以访问同一数据库,只要它们访问不同的表即可。
表级锁的限制比数据库级锁的限制少,但是当许多事务正在等待访问同一张表时,会导致流量阻塞。如果在不同的事务需要访问同一表的不同部分时(即,当事务不会相互干扰时)锁强制延迟,则这种情况特别令人讨厌。因此,表级锁不适用于多用户DBMS。图10.4说明了表级锁定的作用。请注意,即使事务T1和T2尝试使用不同的行,它们也不能访问相同的表。 T2必须等待,直到T1解锁表。
页面级(Page Level):页面级锁定中,DBMS锁定整个磁盘页面。磁盘页或页面等效于磁盘块,可以将其描述为磁盘的直接可寻址部分。页面具有固定大小,例如4K,8K或16K。例如,如果您只想向4K页写入73个字节,则必须从磁盘读取整个4K页,在内存中进行更新,然后再写回到磁盘。一个表可以跨越多个页面,而一个页面可以包含一个或多个表的几行。页面级锁定当前是多用户DBMS的最常用锁定方法。页面级锁定的示例如图10.5所示。请注意,T1和T2在锁定不同磁盘页的同时访问同一表。如果T2要求使用位于被T1锁定的页面上的行,则T2必须等待,直到T1解锁页面为止。
行级(Row Level):行级锁的限制要比前面讨论的锁定要少得多。 DBMS允许并发事务访问同一表的不同行,即使这些行位于同一页上也是如此。尽管行级锁定方法提高了数据的可用性,但是其管理仍需要高开销,因为涉及冲突事务的数据库表中的每一行都存在锁定。当应用程序会话在同一页面上请求多个锁时,现代DBMS会将锁从行级别自动升级为页面级别。图10.6说明了行级锁的用法。
请注意,在图10.6中,即使请求的行在同一页面上,两个事务也可以同时执行。 T2仅在请求与T1相同的行时必须等待。
字段级(Field Level):字段级锁允许并发事务访问同一行,只要它们需要在该行中使用不同的字段(属性)即可。尽管字段级锁定显然会产生最灵活的多用户数据访问,但是它很少在DBMS中实现,因为它需要极高级别的计算机开销,并且在实践中行级锁定要有用得多。
5.2 锁的类型(Lock Types)
无论锁的粒度级别如何,DBMS都可以使用不同的锁类型或模式:二进制或共享/独占。
二进制(Binary):二进制锁只有两种状态:锁定(1)或未锁定(0)。如果某个对象(例如数据库,表,页面或行)被事务锁定,则其他任何事务都不能使用该对象。如果对象被解锁,则任何事务都可以锁定该对象以供使用。每个数据库操作都需要锁定受影响的对象。通常,事务必须在对象终止后将其解锁。因此,每个事务都需要对每个访问的数据项进行锁定和解锁操作。这些操作由DBMS自动管理和安排;用户不会锁定或解锁数据项。 (每个DBMS都有默认锁定机制。如果最终用户想要覆盖默认设置,则LOCK TABLE命令和其他SQL命令可用于该目的。)
表10.12中说明了二进制锁定技术,其中使用了表10.4中遇到的丢失更新问题。请注意,锁定和解锁功能消除了
丢失更新问题,因为在WRITE语句完成之前不会释放锁定。因此,PROD_QOH值只有在正确更新后才能使用。但是,现在认为二进制锁过于严格,无法产生最佳的并发条件。例如,DBMS将不允许两个事务读取同一数据库对象,即使这两个事务都不更新数据库,因此也不会发生并发问题。请记住,从表10.11中可以看出,并发冲突仅在两个事务同时执行并且其中一个更新数据库时发生。
共享/独占(Shared/Exclusive):当专门为锁定对象的事务保留访问权限时,存在独占锁。当存在潜在冲突时,必须使用排他锁(请参见表10.11)。当基于公共锁授予并发事务读取访问权限时,存在共享锁。只要所有并发事务都是只读的,共享锁就不会产生冲突。
当事务要从数据库读取数据并且该数据项没有任何排他锁时,将发出共享锁。当事务要更新(写入)数据项并且当前没有任何其他事务对该数据项持有任何锁时,将发出排他锁。使用共享/排他锁概念,锁可以具有三种状态:解锁,共享(读)和排他(写)状态。
如表10.11所示,只有在至少一个是写事务时,两个事务才发生冲突。因为可以一次安全地执行两个读取事务,所以共享锁允许多个读取事务同时读取同一数据项。例如,如果事务T1在数据项X上具有共享锁,而事务T2要读取数据项X,则T2也可以在数据项X上获得共享锁。
如果事务T2更新数据项X,则T2在数据项X上需要排他锁。只有且仅当数据项上没有其他锁时,才授予排他锁(此条件称为互斥规则:仅一个事务一次可以拥有一个对象的排他锁。)因此,如果事务T1已在数据项X上持有共享(或排他)锁,则不能将排他锁授予事务T2,并且T2必须等待开始直到T1提交。换句话说,共享锁将始终阻止排他(写)锁;因此,减少了事务并发。
尽管使用共享锁可以提高数据访问的效率,但是共享/排他锁模式会增加锁管理器的开销,原因有以下几个原因:
•必须先知道持有的锁的类型,然后才能授予锁。
•存在三种锁定操作:READ_LOCK检查锁定类型,WRITE_LOCK发出锁定,以及UNLOCK释放锁定。
•模式已得到增强,可以将锁从共享升级到互斥,并将锁降级从互斥降级到共享。
尽管锁可以防止严重的数据不一致,但是它们可以导致两个主要问题:
•结果交易时间表可能无法序列化。
•日程安排可能会导致死锁。当两个事务无限期地等待彼此解锁数据时,就会发生死锁。当两个或多个事务彼此等待解锁数据时,就会导致数据库死锁,这类似于大城市的交通死锁。
幸运的是,这两个问题都可以解决:可通过称为两阶段锁定的锁定协议实现可串行性,并且可以使用死锁检测和预防技术来管理死锁。接下来的两节将对这些技术进行检查。
5.3 两阶段锁定以确保可串行化(Two-Phase Locking to Ensure Serializability)
两阶段锁定(2pL)定义事务如何获取和放弃锁定。两阶段锁定可确保可序列化,但不能防止死锁。这两个阶段是:
1.增长阶段,其中事务获取所有必需的锁而不解锁任何数据。一旦获取了所有锁,事务就处于其锁定点。
2.缩减阶段,在该阶段中,事务释放所有锁,而无法获得新的锁。
两阶段锁定协议受以下规则支配:
•两个事务不能具有冲突的锁。
•在同一事务中,没有解锁操作可以在锁定操作之前进行。
•在获得所有锁之前,即在事务处于其锁定点之前,不会影响任何数据。
图10.7描述了两阶段锁定协议。
在此示例中,事务首先获取它需要的两个锁。当它具有两个锁时,它将达到其锁定点。接下来,修改数据以符合交易要求。最终,事务在释放第一阶段中获取的所有锁时完成。两阶段锁定会增加交易处理成本,并可能导致其他不良后果,例如死锁。
5.4 死锁(Deadlocks)
当两个事务无限期地等待彼此解锁数据时,就会发生死锁。例如,当以以下方式存在两个事务T1和T2时,将发生死锁:
T1 =访问数据项X和Y
T2 =访问数据项Y和X
如果T1尚未解锁数据项Y,则T2无法开始。如果T2尚未解锁数据项X,则T1无法继续。因此,T1和T2各自等待对方解锁所需的数据项。这种僵局也称为致命拥抱。表10.13演示了如何创建死锁条件。
前面的示例仅使用两个并发事务来演示死锁情况。在实际的DBMS中,可以同时执行更多事务,从而增加了产生死锁的可能性。请注意,只有在事务之一想要获得数据项的排他锁时才可能发生死锁。共享锁之间不能存在死锁条件。
控制死锁的三种基本技术是:
•防止死锁(Deadlock prevention)。当有可能发生死锁时,请求新锁的事务将中止。如果事务中止,则将回滚此事务所做的所有更改,并释放该事务获得的所有锁。然后重新安排事务以执行。防止死锁之所以起作用,是因为它避免了导致死锁的情况。
•死锁检测(Deadlock detection)。 DBMS定期测试数据库是否有死锁。如果发现死锁,则“受害者”事务中止(回滚并重新启动),其他事务继续。
•避免死锁(Deadlock avoidance)。事务必须先获得所需的所有锁,然后才能执行。该技术通过要求连续获取锁来避免冲突事务的回滚。但是,避免死锁所需的串行锁分配会增加操作响应时间。
使用哪种死锁控制方法的选择取决于数据库环境。例如,如果死锁的可能性低,则建议检测死锁。但是,如果出现死锁的可能性很高,则建议防止死锁。如果系统的优先级列表上的响应时间不高,则可以避免死锁。当前所有的DBMS在事务数据库中都支持死锁检测,而某些DBMS对其他类型的数据(例如数据仓库或XML数据)使用了混合的预防和避免技术。
6.带时间戳的并发控制方法(Concurrency Control with time stampin Methods)
用于调度并发事务的时间戳方法为每个事务分配了全局唯一时间戳。时间戳记值产生一个明确的顺序,在该顺序中,事务将提交给DBMS。时间戳记必须具有两个属性:唯一性和单调性。唯一性确保不会存在相等的时间戳记值,而单调性1可确保时间戳记值始终增加。
同一事务中的所有数据库操作(读取和写入)必须具有相同的时间戳。 DBMS按时间戳顺序执行冲突的操作,从而确保事务的可序列化性。如果有两个事务冲突,则将其中一个事务停止,回滚,重新安排并分配新的时间戳值。
时间戳方法的缺点是,数据库中存储的每个值都需要两个附加的时间戳字段:一个用于最后一次读取该字段,另一个用于最后一次更新。因此,时间戳会增加内存需求和数据库的处理开销。时间戳记需要大量系统资源,因为可能必须停止,重新安排和重新安排许多事务。
6.1 等待/死亡和伤口/等待方案(Wait/Die and Wound/Wait Schemes)
时间戳方法用于管理并发事务执行。在本节中,您将了解两种用于决定回滚哪个事务并继续执行的方案:等待/死亡方案和清盘/等待方案。 2一个示例说明了差异。假设您有两个相互冲突的事务:T1和T2,每个事务都有唯一的时间戳。假设T1的时间戳为11548789,T2的时间戳为19562545。您可以从这些时间戳中推断出T1是较旧的事务(较低的时间戳值),而T2是较新的事务。在这种情况下,表10.14显示了四种可能的结果。
使用等待/死方案:
•如果请求锁的事务是两个事务中的较早的事务,它将等待直到另一个事务完成并释放锁。
•如果请求锁定的事务是两个事务中的较小者,它将死(回退)并使用相同的时间戳进行重新安排。
简而言之,在等待/死方案中,较旧的事务等待较年轻的事务完成并释放其锁。
在伤口/等待方案中:
•如果请求锁定的事务是两个事务中的较早事务,它将通过回滚来抢占(取消)较年轻的事务。当T1回滚T2时,T1抢占T2。使用相同的时间戳重新安排较年轻的抢占式交易。
•如果请求锁的事务是两个事务中的较小者,它将等待直到另一个事务完成并释放锁。
简而言之,在“等待/等待”方案中,较旧的事务将回滚较年轻的事务并重新安排其时间。
在这两种方案中,一个事务都等待另一个事务完成并释放锁。但是,在许多情况下,一个事务请求多个锁。事务必须等待每个锁定请求多长时间?显然,这种情况可能导致某些事务无限期地等待,从而导致死锁。为防止死锁,每个锁定请求都有一个关联的超时值。如果在超时到期之前未授予锁定,则事务将回滚。
7. 乐观方法的并发控制(Concurrency Control with optimistic Methods)
乐观方法基于大多数数据库操作不冲突的假设。乐观方法既不需要锁定也不需要时间戳技术。取而代之的是,事务在提交之前不受限制地执行。使用乐观方法,每个事务都经过两个或三个阶段,称为读取,验证和写入。
•在读取阶段,事务将读取数据库,执行所需的计算,并对数据库值的专用副本进行更新。事务的所有更新操作都记录在一个临时更新文件中,其余事务不会访问该文件。
•在验证阶段,对事务进行验证,以确保所做的更改不会影响数据库的完整性和一致性。如果验证测试为肯定,则事务进入写入阶段。如果验证测试是否定的,则重新启动事务,并放弃更改。
•在写阶段,更改将永久应用于数据库。
对于大多数需要很少更新事务的读取或查询数据库系统,乐观方法是可以接受的。在频繁使用的DBMS环境中,死锁的管理(预防和检测死锁)构成了重要的DBMS功能。 DBMS将使用这里讨论的一种或多种技术,以及这些技术的变体。为了进一步了解如何在数据库中实现事务管理,了解ANSI SQL 1992标准中定义的事务隔离级别非常重要。
悲观锁(pessimistic locks):假设会发生冲突而放置的锁。
8. AnsI事务隔离级别(AnsI Levels of transaction Isolation)
ANSI SQL标准(1992)基于事务隔离级别定义了事务管理。事务隔离级别是指将事务数据与其他并发事务“保护或隔离”的程度。根据其他事务在执行期间可以看到(读取)的数据来描述隔离级别。更准确地说,事务隔离级别由事务允许或不允许的“读取”类型描述。读取操作的类型为:
•脏读:事务可以读取尚未提交的数据。
•不可重复读取:事务在时间t1读取给定的行,然后在时间t2读取同一行,产生不同的结果。原始行可能已被更新或删除。
•幻像读取:事务在时间t1执行查询,然后在时间t2运行相同的查询,产生满足该查询的其他行。
基于上述操作,ANSI定义了四个事务隔离级别:未提交读,已提交读,可重复读和可序列化。表10.15显示了四个ANSI事务隔离级别。该表还显示了Oracle和MS SQL Server数据库提供的其他隔离级别。
读取未提交的数据将从其他事务中读取未提交的数据。在此隔离级别上,数据库不会在数据上放置任何锁,这可以提高事务性能,但会以数据一致性为代价。 read Committed强制事务仅读取已提交的数据。这是大多数数据库(包括Oracle和SQL Server)的默认操作模式。在此级别上,数据库将对数据使用排他锁,从而导致其他事务等待原始事务提交。可重复的读取隔离级别可确保查询返回一致的结果。这种隔离级别使用共享锁来确保其他事务在原始查询读取行后不会更新该行。但是,将读取新行(幻像读取),因为在第一个查询运行时这些行不存在。可序列化隔离级别是ANSI SQL标准定义的最严格的级别。但是,需要特别注意的是,即使具有可序列化的隔离级别,也始终可能出现死锁。大多数数据库使用死锁检测方法进行事务管理,因此,它们将在事务验证阶段检测到“死锁”并重新安排事务的时间。
隔离级别不同的原因是为了增加事务并发性。隔离级别从限制最小(读取未提交)到限制更大(可序列化)。隔离级别越高,就需要更多的锁(共享锁和独占锁)来提高数据一致性,但以事务并发性能为代价。事务的隔离级别在事务语句中定义,例如,使用常规的ANSI SQL语法:
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED
… SQL STATEMENTS….
COMMIT TRANSACTION;
Oracle和MS SQL Server使用SET TRANSACTION ISOLATION LEVEL语句定义隔离级别。 SQL Server支持所有四个ANSI隔离级别。 Oracle默认情况下提供一致的语句级读取,以确保“读取已提交”和“可重复读取”事务。 MySQL使用具有一致快照的START事务来为事务提供一致的读取。也就是说,事务只能在事务开始时看到提交的数据。
从前面的讨论中可以看到,事务管理是一个复杂的主题,数据库利用各种技术来管理事务的并发执行。但是,有时可能有必要采用数据库恢复技术将数据库恢复到一致状态。
9. 数据库恢复管理(Database recovery Management)
数据库恢复将数据库从给定状态(通常不一致)恢复到先前一致的状态。恢复技术基于原子事务属性:事务的所有部分必须被视为单个逻辑工作单元,在其中应用并完成所有操作以生成一致的数据库。如果由于某种原因无法完成事务操作,则必须中止该事务,并且必须回滚(撤消)对数据库的任何更改。简而言之,事务恢复将撤消该事务在中止该事务之前对数据库所做的所有更改。
尽管本章强调了事务的恢复,但是在发生某些类型的严重错误之后,恢复技术也适用于数据库和系统。严重事件可能导致数据库停止工作并损害数据的完整性。严重事件的示例包括:
•硬件/软件故障。这种类型的故障可能是硬盘介质故障,主板上的电容器损坏或存储库故障。此类别下的其他错误原因包括应用程序或操作系统错误,这些错误导致数据被覆盖,删除或丢失。一些数据库管理员认为这是数据库问题的最常见来源之一。
•人为事件。此类事件可以分为无意或有意事件。
–粗心的最终用户会导致意外故障。这些错误包括从表中删除错误的行,按键盘上的错误键或意外关闭主数据库服务器。
–故意事件具有更严重的性质,通常表示公司数据处于严重风险中。在此类别下,安全性威胁是由黑客试图获得对数据资源的未经授权的访问所引起的,以及由不满情绪的员工试图破坏数据库操作并损害公司所造成的病毒攻击。
• 自然灾害。此类别包括火灾,地震,洪水和电源故障。
无论是什么原因,严重错误都可能使数据库进入不一致状态。下一节介绍了用于将数据库从不一致状态恢复到一致状态的各种技术。
9.1 事务恢复(Transaction recovery)
在第10-1d节中,您了解了事务日志以及它如何包含用于数据库恢复的数据。数据库事务恢复使用事务日志中的数据将数据库从不一致状态恢复到一致状态。
在继续之前,请研究影响恢复过程的四个重要概念:
•预写日志协议可确保在实际更新任何数据库数据之前始终写入事务日志。该协议确保在发生故障的情况下,以后可以使用事务日志中的数据将数据库恢复到一致状态。
•冗余的事务日志(事务日志的多个副本)确保物理磁盘故障不会损害DBMS的数据恢复能力。
•数据库缓冲区是主内存中的临时存储区,用于加快磁盘操作。为了缩短处理时间,DBMS软件从物理磁盘读取数据,并将其副本存储在主内存的“缓冲区”中。当事务更新数据时,它实际上会更新缓冲区中数据的副本,因为该过程比每次访问物理磁盘都要快得多。稍后,所有包含更新数据的缓冲区都将在一次操作中写入物理磁盘,从而节省了大量的处理时间。
•数据库检查点是DBMS将内存中所有已更新缓冲区(也称为脏缓冲区)写入磁盘的操作。发生这种情况时,DBMS不会执行任何其他请求。检查点操作也被注册在事务日志中。作为此操作的结果,物理数据库和事务日志将同步。此同步是必需的,因为更新操作将更新缓冲区中而不是物理数据库中的数据副本。 DBMS根据某些操作参数(对于事务日志大小或未完成的事务来说,是高水位标记)自动定期地执行检查点,但也可以显式(作为数据库事务语句的一部分)或隐式(作为一部分)执行检查点数据库备份操作)。当然,检查点太频繁会影响事务性能。检查点太少会影响数据库恢复性能。无论如何,检查点都是非常实用的功能。正如您接下来将看到的,检查点在事务恢复中也起着重要的作用。
数据库恢复过程涉及在发生故障后使数据库进入一致状态。事务恢复过程通常使用延迟写入和直写技术。
当恢复过程使用延迟写入技术(也称为延迟更新)时,事务操作不会立即更新物理数据库。而是,仅更新事务日志。使用事务日志中的信息,仅使用提交的事务中的数据对数据库进行物理更新。如果事务在到达提交点之前中止,则无需更改数据库(无需ROLLBACK或undo),因为它从未更新。所有已启动和已提交事务的恢复过程(失败之前)遵循以下步骤:
1.确定事务日志中的最后一个检查点。这是上次将事务数据实际保存到磁盘上的时间。
2.对于在最后一个检查点之前启动并提交的事务,无需执行任何操作,因为数据已经保存。
3.对于在最后一个检查点之后执行提交操作的事务,DBMS使用事务日志记录中的“之后”值,使用事务日志记录来重做事务并更新数据库。更改是按照从旧到新的升序进行的。
4.对于在最后一个检查点之后进行ROLLBACK操作或在发生故障之前保持活动状态(既没有COMMIT也没有ROLLBACK)的任何事务,都不需要执行任何操作,因为数据库从未更新过。
当恢复过程使用直写技术(也称为即时更新)时,即使在交易到达其提交点之前,交易操作也会在交易执行期间立即更新数据库。如果事务在到达其提交点之前中止,则需要执行ROLLBACK或undo操作才能将数据库还原到一致状态。在这种情况下,ROLLBACK操作将使用“之前”值的事务日志。恢复过程遵循以下步骤:
1.确定事务日志中的最后一个检查点。这是上次将事务数据实际保存到磁盘上的时间。
2.对于在最后一个检查点之前启动并提交的事务,无需执行任何操作,因为数据已经保存。
3.对于在最后一个检查点之后提交的事务,DBMS使用事务日志的“之后”值重新执行该事务。更改从最早到最新以升序应用。
4.对于在最后一个检查点之后执行ROLLBACK操作或在发生故障之前保持活动状态(既没有COMMIT也没有ROLLBACK)的任何事务,DBMS使用事务日志记录来ROLLBACK或撤消操作,使用“交易记录中的“之前”值。更改以从最新到最早的相反顺序应用。
使用表10.16中的事务日志来跟踪简单的数据库恢复过程。为了确保您了解恢复过程,简单事务日志包括三个事务和一个检查点。该事务日志包括本章前面使用的事务组件,因此您应该已经熟悉基本过程。给定事务,事务日志具有以下特征:
•事务101由两个UPDATE语句组成,这两个语句减少了产品54778-2T的现有数量,并为两个产品54778-2T的信用销售而增加了客户10011的客户余额。
•交易106与您在第10-1a节中看到的相同的信用销售事件。此交易代表将一台产品89-WRE-Q赊销给客户10016的价格为$ 277.55。此事务由五个SQL DML语句组成:三个INSERT语句和两个UPDATE语句。
•事务155代表简单的库存更新。该事务由一个UPDATE语句组成,该语句将手头2232 / QWE产品的数量从6个增加到26个。
•数据库检查点将所有更新的数据库缓冲区写入磁盘。检查点事件仅写入所有先前提交的事务的更改。在这种情况下,检查点将事务101所做的所有更改应用于数据库数据文件。
使用表10.16,现在可以使用延迟更新方法来跟踪DBMS的数据库恢复过程,如下所示:
1.确定最后一个检查点,在本例中为TRL ID423。这是最后一次将数据库缓冲区物理写入磁盘。
2.请注意,事务101在最后一个检查点之前开始和完成。因此,所有更改都已写入磁盘,无需采取任何其他措施。
3.对于在最后一个检查点(TRL ID 423)之后提交的每个事务,DBMS将使用“后”值使用事务日志数据将更改写入磁盘。例如,对于事务106:
a. 查找COMMIT(TRL ID 457)。
b. 使用先前的指针值来定位事务的开始(TRL ID 397)。
C. 使用下一个指针值定位每个DML语句,并使用“ after”值将更改应用于磁盘。 (从TRL ID 405开始,然后是415、419、427和431。)请记住,TRL ID 457是此事务的COMMIT语句。
d. 对事务155重复该过程。
4.任何其他交易将被忽略。因此,对于以ROLLBACK结尾的事务或保持活动状态的事务(未以COMMIT或ROLLBACK结尾的事务),由于未将任何更改写入磁盘,因此不会执行任何操作。