PAT选项,这个代码会前滚所有完成的事务到第2个事务日志的结尾。
?
或者我们可以在特定日志文件里事务记录的时间范围里指定时间。这样的话,
数据库会恢复到指定时间的最后一次提交的事务。当你知道你想恢复的时间点,却不知道那个时间包含哪些日志备份时,这个非常重要。
?
还有可能恢复到指定标记的事务。这是很有用的,例如,你要恢复被特定程序访问多个
数据库,到逻辑一致的时间点。这个话题在这里不会详细讨论,你可以参看下微软的在线帮助(https://msdn.microsoft.com/zh-cn/library/ms187014.aspx),另外Mladen Prajdic也提供了一个很好的例子:http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx。
?
“错误事务”后恢复
在任何数据库故障上下文之外,还有必要恢复数据库备份,加上事务日志,为了回到数据库的指定时间点,在错误的数据修改之前,例如删除表或清空表。
?
对此情况你的响应取决于问题本身。如果可能的话,你可能从数据库中断所有用户的连接(在通知它们后),评估下所发生的影响。在某些情况下,你需要估计下问题发生的时间,然后进行数据库完整恢复,恢复到日志使用的时间点。一旦恢复完成,你必须通知用户有些事务可能已经丢失,请求谅解。
?
当然,你不能经常在这个方式里中断正常业务操作来修正一个突发的数据丢失。因为现在的数据库还是在线,在运行,在被用户访问,你只能在STANDBY模式里尝试恢复数据库备份。这允许进一步的日志备份恢复,不像使用NORECOVERY,数据库还是可以访问的。恢复计划会如下:
?
在STANDBY模式里恢复数据库备份,在当前数据库旁(新建一个数据库)。
回滚记录到在错误事务发生,数据丢失前的时间点。
拷贝丢失的数据到当前数据库并删除恢复副本(新建的数据库)。
当然,这个过程并不简单,它会非常耗时。除非你购买了特定的日志读取工具,可以直接访问日志备份,前滚日志意味着一系列涉及到日志恢复,检查数据,进一步还原等等痛苦步骤,直到找出具体发生错误日志的位置。第3步也会非常困难,因为你在当前实时的
系统里引入数据,要和当前数据库状态必须一致,因此会有一致性的问题。
?
我们来看下上述第1步和第2步实现的例子。
?
首先我们通过下列脚本重新创建TestDB数据库,在新的LogTest表里插入10条测试记录。
1 USE master
2 GO
3
4 IF EXISTS ( SELECT name
5 FROM sys.databases
6 WHERE name = 'TestDB' )
7 DROP DATABASE TestDB ;
8
9 CREATE DATABASE TestDB ON
10 (
11 NAME = TestDB_dat,
12 FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\TestDB.mdf'
13 ) LOG ON
14 (
15 NAME = TestDB_log,
16 FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\TestDB.ldf'
17 ) ;
18
19 USE TestDB
20 GO
21 IF OBJECT_ID('dbo.LogTest', 'U') IS NOT NULL
22 DROP TABLE dbo.LogTest ;
23 SELECT TOP 10
24 SomeID = IDENTITY( INT,1,1 ),
25 SomeInt = ABS(CHECKSUM(NEWID())) % 50000 + 1 ,
26 SomeLetters2 = CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65)
27 + CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65)
28 INTO dbo.LogTest
29 FROM sys.all_columns ac1
30 CROSS JOIN sys.all_columns ac2 ;
31 GO
32 USE master
33 GO
?
?
在代码5.6里,我们直接进行一个完整数据库备份(覆盖先前的任何备份文件)。你需要创建“Backups”目录,如果你已经做了,或者调整到合适目录。
?
1 -- full backup of the database
2 BACKUP DATABASE TestDB
3 TO DISK ='C:\Backups\TestDB.bak'
4 WITH INIT;
5 GO
(代码5.6:TestDb的完整备份)
?
然后我们插入一条新纪录到LogTest表。
?
?
?1 USE TestDB
?2 GO
?3 INSERT INTO [TestDB].[dbo].[LogTest]
?4 ? ? ? ? ? ?([SomeInt]
?5 ? ? ? ? ? ?,[SomeLetters2])
?6 ? ? ?VALUES
?7 ? ? ? ? ? ?(66666,
?8 ? ? ? ? ? ?'ST')
?9 ? ? ? ? ? ?
10 SELECT * FROM dbo.LogTest
?
(代码5.7:插入TestDB第11行)
?
现在我们当前TestDB数据库的LogTest表有11条记录,备份版本里有10条记录。现在我们在日志备份里捕获额外的修改,如代码5.8所示:
?
1 USE master
2 GO
3 BACKUP Log TestDB
4 TO DISK ='C:\Backups\TestDB_log.bak'
5 WITH INIT;
6 GO
(代码5.8:TestDB的日志备份)
?
现在,我们来模拟一个错误的“坏事务”,直接删除LogTest表,之后我们进行最后日志备份。
?
?
?1 USE TestDB
?2 GO
?3 DROP TABLE dbo.LogTest ;
?4?
?5 USE master
?6 GO
?7 BACKUP Log TestDB
?8 TO DISK ='C:\Backups\TestDB_log2.bak'
?9 WITH INIT;
10 GO
?
(代码5.9:灾难发生!)
?
为了尝试找回丢失的数据,不中断正常业务操作,我们来还原一个在STANDBY模式里TestDB数据库的副本。Standby模式数据库的数据和日志叫做ANewTestDB,移动到”Standby“目录(你要事先创建这个目录)。
?
?
?1 -- restore a copy of the TestDB database, called
?2 -- ANewTestDB, in STANDBY mode