技术开发 频道

DB2崩溃后用事务日志恢复的原理与技巧

【IT168技术文档】在系统崩溃之后,使用DB2的事务日志恢复数据库。

您曾多少次碰到过错误消息“SQL0946C The transaction log for the database is full?”

在尽力解决该问题时,您是否停下来思考如下两个问题:1. 为何存在事务日志;2. 事务日志记录服务的目的是什么呢?

若没有事务,多个用户和应用程序同时与一个数据库进行交互时就必然会破坏数据。而如果没有事务日志记录,DB2 UDB中的一些据库恢复方法就不会存在。

如果您还没有完全理解这些概念,也不必担忧。我将解释事务是什么以及事务日志记录背后的机制。然后,我将展示在系统崩溃或程序故障之后,如何使用数据库事务日志文件中所存储的信息来使数据库回归到一致、可用的状态。

您还可以通过这些重要的日志做更多事情。在今后的专栏中,我将展示如何使用事务日志文件重现操作,以将数据库恰好恢复到给定时间点所处的状态。

事务

事务(也称作工作单元)是指一个或多个SQL操作的序列,这些操作组合成一个单元且通常位于一个应用程序进程内。该单元通常称作是“原子的”,因为它是不可分的——它的所有工作要么全都执行,要么全都不执行。一个给定的事务可以执行任何数目的SQL操作(从一个到几千个,取决于业务逻辑里对于“一步”的定义)。

一个事务的开始和终止定义了数据库里数据一致性的点;要么将事务里所执行的所有操作的结果应用到数据库上,并使之成为永久的(已提交),要么将之都撤销(回滚),使数据库返回到启动该事务之前的状态。

事务是在建立到数据库的连接之后第一次执行SQL语句时或在现有事务终止时立即启动。一旦启动,就可以使用名为原子提交的功能隐式地终止该事务。通过原子提交,会将每条可执行的SQL语句当作一个事务。如果该语句执行成功,那它所做的任何修改都将应用到数据库上,但如果语句失败,那修改将被丢弃。

还可以通过执行COMMIT或ROLLBACK SQL语句显式地终止事务。

这些语句的基本语法是:
COMMIT <WORK> ROLLBACK <WORK>
在COMMIT终止事务时,会将该事务从开始时对数据库所做的所有修改变成永久性的。使用ROLLBACK,所有修改都将撤销。

事务所做的未提交的修改对其他用户和应用程序来说是无法访问的,除非那些用户和应用程序使用的是未提交读(UR)隔离。然而,一旦提交了事务所做的修改,它们对于所有其他用户和应用程序来说就都是可以访问的了,并且只能通过执行新事务中的新SQL语句来删除。

事务日志记录

在向一个基表进行INSERT时,首先在缓冲池中创建一条记录,该缓冲池与指定该表的数据存储于何处的表空间相关联。每次更新或删除一条记录时,就从存储器中检索包含该记录的页面,并复制到适当的缓冲池中,然后由UPDATE/DELETE进行修改。一旦进行了这一修改,就会向日志缓冲器写入一条反映该动作的记录,日志缓冲器是内存中的另一指定存储区(为日志缓冲器预留的真正存储大小是由logbufsiz数据库配置参数控制的)。如果执行INSERT,就会写入一条包含了新行数据值的记录。当出现删除时,就写入一条包含了该行原始值的记录。如果执行UPDATE,就写入一条包含了该行原始值和新值的记录(在大多数情况下,通过用该行的更新值在原始值上执行EXCLUSIVE OR,为更新操作生成日志记录)。最终,当执行INSERT、UPDATE或DELETE的事务终止时,就将相应的COMMIT或ROLLBACK记录写入日志缓冲器。

每当激活缓冲池I/O页面清理器,日志缓冲器本身已满,或者提交或回滚事务时,就立即将日志缓冲器中存储的所有记录写入磁盘上所存储的一个或多个事务日志文件中。如果发生系统故障,日志缓冲器的不断刷新将最小化可能丢失的日志记录数目。一旦将与特定事务相关联的所有日志记录(包括相应的COMMIT或ROLLBACK记录)成功具体化(externalize)为一个或多个日志文件,就会将事务本身的结果复制到适当的表空间容器以永久存储(已修改的数据页本身仍保留在内存中,在必要时可以快速进行访问;它们最终将被改写)。该过程称作写前日志记录(write-ahead logging),保证对数据所做的修改在记录到数据库之前,总是被具体化为日志文件。见下图:

因为多个事务可以在任何时候使用一个数据库,所以一个日志文件可能包含属于几个不同事务的日志记录。为了追踪一条日志记录属于哪个事务,要给每条日志记录分配一个特殊的事务ID,将之绑定到创建它的事务。通过使用事务ID,可以随时将与特定事务相关联的日志记录写入一个或多个日志文件,而不影响数据一致性——最终,对于终止该事务的操作的COMMIT或ROLLBACK记录也将进行日志记录。

崩溃恢复

在还未提交事务的修改之前,如果发生问题——例如,发生停电或应用程序异常终止——会发生什么事情呢?事务所做的任何未提交或已回滚的工作都将丢失。此外,如果正在将其数据具体化(externalize)到数据库的已提交事务遭到破坏,该数据库将处于不一致、不可用的状态(每当尝试建立连接时,不一致的数据库将生成返回代码和错误消息)。您无法恢复内存中所存储的事务记录,但是可以通过执行名为崩溃恢复的操作,将不一致的数据库恢复为一致、可用的状态。

启动崩溃恢复的最常用方法就是从DB2命令行处理器(DB2 Command Line Processor,CLP)执行RESTART命令。该命令的基本语法是:
RESTART [DATABASE | DB] [DatabaseName] USER [UserName] < USING [Password] > > < DROP PENDING TABLESPACES ( [TS_Name] , ... ) > < WRITE RESUME >
其中:

DatabaseName 指示分配给尝试进行恢复的数据库的名称。

UserName 指示分配给用户的名称,崩溃恢复将在该用户的权限下执行。

Password 指示与用户名称相对应的密码,崩溃恢复将在该用户的权限下执行。

TS_Name 指示分配给一个或多个表空间的名称,如果在尝试将表空间恢复为一致状态时碰到错误,那么这些表空间将被禁用或置为Drop Pending模式。

注意:尖括号(< >)中显示的参数是可选的;方括号([ ])中显示的参数是必需的;逗号后面加省略号(, ...)表示前面的参数可以重复多次。关于 RESTART 命令的完整语法,请参阅IBM DB2 Universal Database, Version 8 Command Reference(ftp.software.ibm.com/ps/products/db2/info/vr8/pdf/letter/db2n0e80.pdf)。

如果需要在名为SAMPLE的数据库上执行崩溃恢复操作,就执行RESTART DATABASE SAMPLE命令。

您还可以配置数据库,以便每当用户或应用程序尝试连接处于不一致状态时,它就会自动启动崩溃恢复。仅仅需要将值ON分配给数据库的AUTORESTART配置参数(每当激活数据库或尝试建立连接时,DB2 Database Manager就检查数据库的状态。当autorestart配置参数设置为ON时,如果数据库处于不一致的状态,Database Manager就自动执行RESTART命令)。

在进行崩溃恢复时,将分析数据库事务日志文件中存储的记录,并将每条具有相应COMMIT记录的事务记录重新应用到数据库。重现然后撤销没有相应COMMIT记录的所有记录(这就是为何要为所有更新操作记录前后信息的原因)。因为日志记录频繁进行具体化,且由特定事务所做的修改只有当事务本身成功终止时才进行具体化,所以在故障之后将数据库恢复到一致性状态的能力总是能得到保证。

崩溃恢复只是事务日志所提供的功能中的一种。在处理前滚恢复时,我将展示如何可以使用事务日志文件中所存储的记录将数据库恢复到任何指定时间点所处的状态。但是您首先需要理解备份映像和版本恢复等概念,我将在下一专栏中介绍这两个主题。
0
相关文章