使用标记事务以一致地恢复相关数据库(完整恢复模式)

本主题仅适用于使用完整或大容量日志恢复模式的 SQL Server 数据库。

对两个或多个数据库( 相关数据库)进行相关更新时,可以使用事务标记将它们恢复到逻辑一致性点。 但是,此恢复过程会丢失在作为恢复点的标记设定后提交的任何事务。 标记事务仅适用于测试相关数据库或在您愿意丢失最近提交的事务时。

定期标记每个相关数据库中的相关事务会在数据库中建立一系列常见的恢复点。 事务标记记录在事务日志中,并包含在日志备份中。 发生灾难时,可以将每个数据库还原到相同的事务标记,以将它们恢复到一致点。

注释

可以独立创建不同数据库上的日志备份,不必同时创建。

在以下情境中恢复相关数据库需要您已在每个相关数据库中标记事务:

  • 销毁一个或多个事务日志。 必须在上次日志备份时将数据库集还原到一致状态。

  • 必须在早期某个时间点将整个数据库集还原到相互一致的状态。

重要

只能将相关数据库恢复到标记的事务,而不能恢复到特定的时间点。

有关如何创建标记事务的信息,请参阅本主题后面的“标记事务的创建”。

使用标记事务的典型场景

使用标记事务的典型方案包括以下步骤:

  1. 创建每个相关数据库的完整或差异数据库备份。

  2. 在所有数据库中标记一个事务块。

  3. 备份所有数据库的事务日志。

  4. 使用 NORECOVERY 还原数据库备份。

  5. 使用 STOPATMARK 还原日志。

使用标记事务的注意事项

在事务日志中插入命名标记之前,请考虑以下事项:

  • 由于事务标记使用日志空间,因此仅用于在数据库恢复策略中扮演重要角色的事务。

  • 在标记的事务提交后,在 msdblogmarkhistory 表中插入一行。

  • 如果标记的事务跨越同一数据库服务器或不同服务器上的多个数据库,则必须将所有受影响的数据库的日志中记录这些标记。

创建标记的事务

若要创建标记的事务,请使用 BEGIN TRANSACTION 语句和 WITH MARK [description] 子句。 可选 说明 是标记的文本说明。 需要事务的标记名称。 可以重复使用标记名称。 事务日志记录标记名称、说明、数据库、用户、日期/时间信息和日志序列号(LSN)。 日期/时间信息与标记名称一起使用,用于唯一标识标记。

若要在一组数据库中创建标记的事务,

  1. 在 BEGIN TRAN 语句中命名事务并使用 WITH MARK 子句

    可以在现有事务中嵌套语句 BEGIN TRAN new_mark_name WITH MARK。 new_mark_name的值是事务的标记名称,即使事务拥有事务名称。

    注释

    如果发出第二个嵌套的 BEGIN TRAN...WITH MARK,该语句会被跳过,但会触发一条警告消息。

  2. 针对集中的所有数据库运行更新。

    特定事务的标记仅插入事务日志中的服务器实例,其中 BEGIN TRAN...执行 WITH MARK 语句。 事务标记被放置在服务器实例中每个被标记事务更新的数据库的事务日志中。 如果数据库位于不同的服务器实例上,则必须在每个服务器实例上创建相同的标记。

例子

以下示例将事务日志还原到已命名 ListPriceUpdate事务中的标记。

USE AdventureWorks  
GO  
BEGIN TRANSACTION ListPriceUpdate  
   WITH MARK 'UPDATE Product list prices';  
GO  
  
UPDATE Production.Product  
   SET ListPrice = ListPrice * 1.10  
   WHERE ProductNumber LIKE 'BK-%';  
GO  
  
COMMIT TRANSACTION ListPriceUpdate;  
GO  
  
-- Time passes. Regular database   
-- and log backups are taken.  
-- An error occurs in the database.  
USE master  
GO  
  
RESTORE DATABASE AdventureWorks  
FROM AdventureWorksBackups  
WITH FILE = 3, NORECOVERY;  
GO  
  
RESTORE LOG AdventureWorks  
   FROM AdventureWorksBackups   
   WITH FILE = 4,  
   RECOVERY,   
   STOPATMARK = 'ListPriceUpdate';  

强制标记传播到其他服务器

事务标记名称不会自动分发到另一台服务器,因为事务分散在那里。 若要强制标记分散到其他服务器,必须编写包含 BEGIN TRAN 名称 WITH MARK 语句的存储过程。 然后,必须在源服务器中事务范围下的远程服务器上执行该存储过程。

例如,请考虑在 SQL Server 的多个实例上存在的已分区数据库。 在每个实例上都是一个名为 的数据库。 首先,在每个数据库中,创建一个存储过程,例如 sp_SetMark

CREATE PROCEDURE sp_SetMark  
@name nvarchar (128)  
AS  
BEGIN TRANSACTION @name WITH MARK  
UPDATE coyote.dbo.Marks SET one = 1  
COMMIT TRANSACTION;  
GO  

接下来,创建一个存储过程 sp_MarkAll,其中包含一个用于在每个数据库中放置标记的事务。 sp_MarkAll 可以从任何实例运行。

CREATE PROCEDURE sp_MarkAll  
@name nvarchar (128)  
AS  
BEGIN TRANSACTION  
EXEC instance0.coyote.dbo.sp_SetMark @name  
EXEC instance1.coyote.dbo.sp_SetMark @name  
EXEC instance2.coyote.dbo.sp_SetMark @name  
COMMIT TRANSACTION;  
GO  

Two-Phase 提交

提交分布式事务分为两个阶段:准备和提交。 在提交标记事务时,标记事务中每个数据库的提交日志记录将放置在日志中,在那时任何日志中都没有未决事务。 此时,可以保证没有事务在一个日志中显示为已提交,但未在另一个日志中提交。

以下步骤在提交被标记的事务期间完成这些操作:

  1. 标记事务的准备阶段会停止所有新的准备和提交。

  2. 仅允许已准备好的事务的提交继续。

  3. 标记事务,然后等待所有准备好的事务耗尽,设定超时。

  4. 已标记的事务已准备好并已提交。

  5. 删除了新准备和提交过程中的障碍。

跨多个数据库的标记事务导致的延迟可能会降低服务器的事务处理性能。

建议不要运行并发标记事务。 虽然很少见,但提交分布式标记事务确实有可能与同时提交的其他分布式标记事务发生死锁。 发生这种情况时,标记事务会被选择为死锁受害者,并被回滚。 发生此错误时,应用程序可以重试标记的事务。 当多个标记的事务尝试同时提交时,更可能发生死锁。

恢复到已标记交易的状态

有关如何将包含已标记事务的数据库恢复到特定标记或之前的方法,请参阅 恢复包含标记事务的相关数据库

另请参阅

开始分布式事务(Transact-SQL)
系统数据库的备份和还原 (SQL Server)
BEGIN TRANSACTION (Transact-SQL)
应用事务日志备份 (SQL Server)
完整数据库备份 (SQL Server)
RESTORE (Transact-SQL)
恢复包含已标记事务的相关数据库