创建并应用初始快照

适用于:SQL Server Azure SQL 托管实例

本主题介绍如何使用 SQL Server Management Studio、Transact-SQL 或复制管理对象 (RMO) 在 SQL Server 中创建和应用初始快照。 使用参数化筛选器的合并发布需要由两部分组成的快照。 有关详细信息,请参阅 为包含参数化筛选器的合并发布创建快照
快照由快照代理在创建发布后生成。 按以下方式生成:

  • 立即。 默认情况下,在新建发布向导中创建合并发布后会立即生成此发布的快照。
  • 在计划时间。 在新建发布向导的 “快照代理” 页面上指定计划时间,或者在使用存储过程或复制管理对象 (RMO) 时指定计划时间。
  • 手动。 从命令提示符或 SQL Server Management Studio 运行快照代理。 有关运行代理的详细信息,请参阅复制代理可执行文件概念启动和停止复制代理 (SQL Server Management Studio)

对于合并复制,每当运行快照代理时都会生成快照。 对于事务复制,是否生成快照取决于发布属性 immediate_sync的设置。 如果该属性设置为 TRUE(使用新建发布向导时的默认设置),则每当运行快照代理时都会生成快照,而且可以随时将其应用到订阅服务器。 如果该属性设置为 FALSE(使用 sp_addpublication时的默认设置),则仅当自上次快照代理运行以来添加了新订阅时,才会生成快照;订阅服务器必须等待快照代理完成,才能实现同步。

默认情况下,快照生成后,它们将保存在位于分发服务器上的默认快照文件夹中。 还可以将快照文件保存在可移动介质(例如可移动磁盘、CD-ROM)上,或者保存在默认快照文件夹以外的位置。 另外,可以压缩文件,以便它们更容易存储和传输以及在订阅服务器上应用快照前后执行脚本。 有关这些选项的详细信息,请参阅 Snapshot Options

如果快照用于使用参数化筛选器的合并发布,则创建快照的过程包括两部分。 首先创建包含复制脚本和已发布对象的架构(但不包含数据)的架构快照。 然后,使用包括脚本、从架构快照复制的架构以及属于订阅分区的数据的快照初始化每个订阅。 有关详细信息,请参阅 Snapshots for Merge Publications with Parameterized Filters

在发布服务器上创建快照并将其存储在默认位置或其他快照位置后,可以将快照传输到订阅服务器并应用。 分发代理(用于快照复制或事务复制)或合并代理(用于合并复制)在初始同步期间将快照传输到订阅服务器上的订阅数据库中并将架构和数据文件应用到此数据库。 默认情况下,如果使用新建订阅向导,在创建订阅后会立即发生初始同步。 此行为由该向导的 “初始化订阅” 页面上的 “初始化时间” 选项控制。 当初始化订阅后生成快照时,除非订阅标记为重新初始化,否则快照不会应用到订阅服务器。 有关详细信息,请参阅 重新初始化订阅

在分发代理或合并代理应用初始快照后,该代理将传播后续更新和其他数据修改。 在向订阅服务器分发并应用快照时,只有那些正在等待初始快照或新建快照的订阅服务器会受到影响。 该发布的其他订阅服务器(即那些已经收到对已发布数据的插入、更新、删除或其他修改内容的订阅服务器)不受影响。

若要查看或修改默认快照文件夹位置,请参阅

默认快照位置

可以在配置分发向导的 “快照文件夹” 页上指定默认快照位置。 有关使用此向导的详细信息,请参阅配置发布和分发。 如果在未配置为分发服务器的服务器上创建发布,请在新建发布向导的 “快照文件夹” 页上指定默认快照位置。 有关使用此向导的详细信息,请参阅创建发布

在“分发服务器属性 - <分发服务器>”对话框的“发布服务器”页上,修改默认快照位置。 有关详细信息,请参阅查看和修改分发服务器和发布服务器属性。 在“发布属性 - <发布>”对话框中设置每个发布的快照文件夹。 有关详细信息,请参阅 View and Modify Publication Properties

修改默认快照位置

  1. 在“分发服务器属性 - <分发服务器>”对话框的“发布服务器”页上,单击要更改其默认快照位置的发布服务器的属性按钮 (...)。

  2. 在“分发服务器属性 - <分发服务器>”对话框中,为“默认快照文件夹”属性输入一个值。

    注意

    快照代理必须对指定的目录具有写权限,而分发代理或合并代理必须具有读权限。 如果使用的是请求订阅,则必须指定一个共享目录作为通用命名约定 (UNC) 路径,如 \\computername\snapshot。 有关详细信息,请参阅保护快照文件夹

  3. 选择“确定”

创建快照

默认情况下,如果运行 SQL Server 代理,在使用“新建发布向导”创建发布后,快照代理将立即生成快照。 然后,默认情况下将由分发代理(对于快照复制和事务复制)或合并代理(对于合并订阅)把此快照应用于所有订阅。 还可以使用 SQL Server Management Studio 和复制监视器生成快照。 有关启动复制监视器的信息,请参阅启动复制监视器

使用 SQL Server Management Studio

  1. 在 Management Studio 中连接到发布服务器,然后展开服务器节点。
  2. 展开 “复制” 文件夹,再展开 “本地发布” 文件夹。
  3. 右键单击要为其创建快照的发布,然后单击 “查看快照代理状态”
  4. 在“查看快照代理状态 - <发布>”对话框中,单击“启动”。
    快照代理生成快照后,将显示一条消息,例如“[100%] 已生成 17 个项目的快照”。

在复制监视器中

  1. 在复制监视器的左窗格中依次展开发布服务器组、发布服务器。
  2. 右键单击要为其生成快照的发布,再单击 “生成快照”
  3. 要查看快照代理的状态,请单击“代理”选项卡。有关更多详细信息,请右键单击网格中的快照代理,然后单击“查看详细信息”

“使用 Transact-SQL”

可通过创建并运行快照代理作业或通过批处理文件运行快照代理可执行文件,以编程方式创建初始快照。 初始快照生成后,该快照将在订阅首次同步时传输并应用到订阅服务器。 如果您在命令提示符处或通过批处理文件运行快照代理,则只要现有快照变为无效,您就需要重新运行此代理。

重要

如果可能,请在运行时提示用户输入安全凭据。 如果必须在脚本文件中存储凭据,则必须保护文件以防止未经授权的访问。

  1. 创建快照发布、事务发布或合并发布。 有关详细信息,请参阅 Create a Publication

  2. 执行 sp_addpublication_snapshot (Transact-SQL)。 指定 @publication 以及下列参数:

    • @job_login ,用于指定快照代理在分发服务器上运行时所用的 Windows 身份验证凭据。

    • @job_password,为提供的 Windows 凭据的密码。

    • (可选)如果代理在连接到发布服务器时将使用 SQL Server 身份验证,则将 @publisher_security_mode 的值指定为 0 。 在这种情况下,您还必须为 @publisher_login@publisher_password指定 SQL Server 身份验证的登录信息。

    • (可选)快照代理作业的同步计划。 有关详细信息,请参阅 Specify Synchronization Schedules

    重要

    使用远程分发服务器配置发布服务器时,为所有参数提供的值(包括 job_loginjob_password)都会以纯文本方式发送到该分发服务器。 在执行此存储过程之前,应该对发布服务器及其远程分发服务器之间的连接进行加密。 有关详细信息,请参阅启用数据库引擎的加密连接(SQL Server 配置管理器)

  3. 向发布添加项目。 有关详细信息,请参阅 定义项目

  4. 在发布服务器上,对发布数据库执行 sp_startpublication_snapshot (Transact-SQL),并指定步骤 1 中 @publication 的值。

应用快照

使用 SQL Server Management Studio

  1. 快照生成后,通过用分发代理或合并代理同步订阅来应用此快照:

    • 如果代理设置为连续运行(事务复制下的默认设置),则快照生成后将自动应用。
    • 如果代理设置为根据计划运行,则在安排代理下次运行时应用快照。
    • 如果代理设置为按需运行,则在您下次运行代理时应用快照。

    有关同步订阅的详细信息,请参阅 Synchronize a Push SubscriptionSynchronize a Pull Subscription文件夹中打开。

使用 Transact-SQL

  1. 创建快照发布、事务发布或合并发布。 有关详细信息,请参阅 Create a Publication

  2. 向发布添加项目。 有关详细信息,请参阅 定义项目

  3. 在命令提示符处或批处理文件中,通过运行 snapshot.exe 并指定下列命令行参数,启动 复制合并代理

    • -Publication
    • -Publisher
    • -Distributor
    • -PublisherDB
    • -ReplicationType

    如果您使用的是 SQL Server 身份验证,则还必须指定下列参数:

    • -DistributorLogin
    • -DistributorPassword
    • -DistributorSecurityMode = \@publisher_security_mode
    • -PublisherLogin
    • -PublisherPassword
    • -PublisherSecurityMode = \@publisher_security_mode

示例 (Transact-SQL)

此示例演示如何创建事务发布,并为新的发布添加快照代理作业(使用 sqlcmd 脚本变量)。 此示例还启动该作业。

-- To avoid storing the login and password in the script file, the values 
-- are passed into SQLCMD as scripting variables. For information about 
-- how to use scripting variables on the command line and in SQL Server
-- Management Studio, see the "Executing Replication Scripts" section in
-- the topic "Programming Replication Using System Stored Procedures".

DECLARE @publicationDB AS sysname;
DECLARE @publication AS sysname;
DECLARE @login AS sysname;
DECLARE @password AS sysname;
SET @publicationDB = N'AdventureWorks2022'; --publication database
SET @publication = N'AdvWorksCustomerTran'; -- transactional publication name
SET @login = $(Login);
SET @password = $(Password);

USE [AdventureWorks]

-- Enable transactional and snapshot replication on the publication database.
EXEC sp_replicationdboption 
  @dbname = @publicationDB, 
  @optname = N'publish',
  @value = N'true';

-- Execute sp_addlogreader_agent to create the agent job. 
EXEC sp_addlogreader_agent 
  @job_login = @login, 
  @job_password = @password,
  -- Explicitly specify the security mode used when connecting to the Publisher.
  @publisher_security_mode = 1;

-- Create new transactional publication, using the defaults. 
USE [AdventureWorks2022]
EXEC sp_addpublication 
  @publication = @publication, 
  @description = N'transactional publication';

-- Create a new snapshot job for the publication, using the defaults.
EXEC sp_addpublication_snapshot 
  @publication = @publication,
  @job_login = @login,
  @job_password = @password;

-- Start the Snapshot Agent job.
EXEC sp_startpublication_snapshot @publication = @publication;
GO

此示例创建一个合并发布,并为此发布添加一个快照代理作业(使用 sqlcmd 变量)。 此示例还启动该作业。

-- To avoid storing the login and password in the script file, the value 
-- is passed into SQLCMD as a scripting variable. For information about 
-- how to use scripting variables on the command line and in SQL Server
-- Management Studio, see the "Executing Replication Scripts" section in
-- the topic "Programming Replication Using System Stored Procedures".

DECLARE @publicationDB AS sysname;
DECLARE @publication AS sysname;
DECLARE @login AS sysname;
DECLARE @password AS sysname;
SET @publicationDB = N'AdventureWorks2022'; 
SET @publication = N'AdvWorksSalesOrdersMerge'; 
SET @login = $(Login);
SET @password = $(Password);

-- Enable merge replication on the publication database.
USE master
EXEC sp_replicationdboption 
  @dbname = @publicationDB, 
  @optname=N'merge publish',
  @value = N'true';

-- Create new merge publication, using the defaults. 
USE [AdventureWorks]
EXEC sp_addmergepublication 
  @publication = @publication, 
  @description = N'Merge publication.';

-- Create a new snapshot job for the publication, using the defaults.
EXEC sp_addpublication_snapshot 
  @publication = @publication,
  @job_login = @login,
  @job_password = @password;

-- Start the Snapshot Agent job.
EXEC sp_startpublication_snapshot @publication = @publication;
GO

以下命令行参数启动快照代理,以为合并发布生成快照。

注意

为便于阅读,添加了换行符。 但在批处理文件中,命令必须位于一行中。

  
REM -- Declare variables  
SET Publisher=%InstanceName%  
SET PublicationDB=AdventureWorks2022   
SET Publication=AdvWorksSalesOrdersMerge   
  
REM --Start the Snapshot Agent to generate the snapshot for AdvWorksSalesOrdersMerge.  
"C:\Program Files\Microsoft SQL Server\120\COM\SNAPSHOT.EXE" -Publication %Publication%   
-Publisher %Publisher% -Distributor %Publisher% -PublisherDB %PublicationDB%   
-ReplicationType 2 -OutputVerboseLevel 1 -DistributorSecurityMode 1  
  

使用复制管理对象 (RMO)

快照代理将在创建发布后生成快照。 可以使用复制管理对象 (RMO) 和直接托管代码对复制代理功能的访问权限以编程的方式生成这些快照。 所使用的对象取决于复制的类型。 可以使用 SnapshotGenerationAgent 对象同步启动快照代理,也可以使用代理作业异步启动快照代理。 初始快照生成后,该快照将在订阅首次同步时传输并应用到订阅服务器。 只要现有快照不再包含有效的最新数据,您就需要重新运行代理。 有关详细信息,请参阅维护发布

重要

如果可能,请在运行时提示用户输入安全凭据。 如果必须存储凭据,请使用 Microsoft Windows .NET Framework 提供的加密服务

通过启动快照代理作业(异步)为快照发布或事务发布生成初始快照

  1. 使用 ServerConnection 类创建与发布服务器的连接。

  2. 创建 TransPublication 类的一个实例。 设置发布的 NameDatabaseName 属性,并将 ConnectionContext 属性设置为步骤 1 中创建的连接。

  3. 调用 LoadProperties 方法以加载该对象的其余属性。 如果此方法返回 false,则说明步骤 2 中的发布属性定义不正确,或者此发布不存在。

  4. 如果 SnapshotAgentExists 的值为 false,请调用 CreateSnapshotAgent 为此发布创建快照代理作业。

  5. 调用 StartSnapshotGenerationAgentJob 方法以启动为此发布生成快照的代理作业。

  6. (可选) SnapshotAvailable 的值为 true时,订阅服务器具有快照。

通过运行快照代理(同步)为快照发布或事务发布生成初始快照

  1. 创建 SnapshotGenerationAgent 类的实例,并设置下列所需属性:

  2. Transactional 的值设置为 SnapshotReplicationType

  3. 调用 GenerateSnapshot 方法。

通过启动快照代理作业(异步)为合并发布生成初始快照

  1. 使用 ServerConnection 类创建与发布服务器的连接。

  2. 创建 MergePublication 类的一个实例。 设置发布的 NameDatabaseName 属性,并将 ConnectionContext 属性设置为步骤 1 中创建的连接。

  3. 调用 LoadProperties 方法以加载该对象的其余属性。 如果此方法返回 false,则说明步骤 2 中的发布属性定义不正确,或者此发布不存在。

  4. 如果 SnapshotAgentExists 的值为 false,请调用 CreateSnapshotAgent 为此发布创建快照代理作业。

  5. 调用 StartSnapshotGenerationAgentJob 方法以启动为此发布生成快照的代理作业。

  6. (可选) SnapshotAvailable 的值为 true时,订阅服务器具有快照。

通过运行快照代理(同步)为合并发布生成初始快照

  1. 创建 SnapshotGenerationAgent 类的实例,并设置下列所需属性:

  2. Merge 的值设置为 ReplicationType

  3. 调用 GenerateSnapshot 方法。

示例 (RMO)

此示例同步运行快照代理,为事务发布生成初始快照。

// Set the Publisher, publication database, and publication names.
string publicationName = "AdvWorksProductTran";
string publicationDbName = "AdventureWorks2022";
string publisherName = publisherInstance;
string distributorName = publisherInstance;

SnapshotGenerationAgent agent;

try
{
    // Set the required properties for Snapshot Agent.
    agent = new SnapshotGenerationAgent();
    agent.Distributor = distributorName;
    agent.DistributorSecurityMode = SecurityMode.Integrated;
    agent.Publisher = publisherName;
    agent.PublisherSecurityMode = SecurityMode.Integrated;
    agent.Publication = publicationName;
    agent.PublisherDatabase = publicationDbName;
    agent.ReplicationType = ReplicationType.Transactional;

    // Start the agent synchronously.
    agent.GenerateSnapshot();

}
catch (Exception ex)
{
    // Implement custom application error handling here.
    throw new ApplicationException(String.Format(
        "A snapshot could not be generated for the {0} publication."
        , publicationName), ex);
}
' Set the Publisher, publication database, and publication names.
Dim publicationName As String = "AdvWorksProductTran"
Dim publicationDbName As String = "AdventureWorks2022"
Dim publisherName As String = publisherInstance
Dim distributorName As String = publisherInstance

Dim agent As SnapshotGenerationAgent

Try
    ' Set the required properties for Snapshot Agent.
    agent = New SnapshotGenerationAgent()
    agent.Distributor = distributorName
    agent.DistributorSecurityMode = SecurityMode.Integrated
    agent.Publisher = publisherName
    agent.PublisherSecurityMode = SecurityMode.Integrated
    agent.Publication = publicationName
    agent.PublisherDatabase = publicationDbName
    agent.ReplicationType = ReplicationType.Transactional

    ' Start the agent synchronously.
    agent.GenerateSnapshot()

Catch ex As Exception
    ' Implement custom application error handling here.
    Throw New ApplicationException(String.Format( _
     "A snapshot could not be generated for the {0} publication." _
     , publicationName), ex)
End Try

此示例异步启动代理作业,为事务发布生成初始快照。

// Set the Publisher, publication database, and publication names.
string publicationName = "AdvWorksProductTran";
string publicationDbName = "AdventureWorks2022";
string publisherName = publisherInstance;

TransPublication publication;

// Create a connection to the Publisher using Windows Authentication.
ServerConnection conn;
conn = new ServerConnection(publisherName);

try
{
    // Connect to the Publisher.
    conn.Connect();

    // Set the required properties for an existing publication.
    publication = new TransPublication();
    publication.ConnectionContext = conn;
    publication.Name = publicationName;
    publication.DatabaseName = publicationDbName;

    if (publication.LoadProperties())
    {
        // Start the Snapshot Agent job for the publication.
        publication.StartSnapshotGenerationAgentJob();
    }
    else
    {
        throw new ApplicationException(String.Format(
            "The {0} publication does not exist.", publicationName));
    }
}
catch (Exception ex)
{
    // Implement custom application error handling here.
    throw new ApplicationException(String.Format(
        "A snapshot could not be generated for the {0} publication."
        , publicationName), ex);
}
finally
{
    conn.Disconnect();
}
' Set the Publisher, publication database, and publication names.
Dim publicationName As String = "AdvWorksProductTran"
Dim publicationDbName As String = "AdventureWorks2022"
Dim publisherName As String = publisherInstance

Dim publication As TransPublication

' Create a connection to the Publisher using Windows Authentication.
Dim conn As ServerConnection
conn = New ServerConnection(publisherName)

Try
    ' Connect to the Publisher.
    conn.Connect()

    ' Set the required properties for an existing publication.
    publication = New TransPublication()
    publication.ConnectionContext = conn
    publication.Name = publicationName
    publication.DatabaseName = publicationDbName

    If publication.LoadProperties() Then
        ' Start the Snapshot Agent job for the publication.
        publication.StartSnapshotGenerationAgentJob()
    Else
        Throw New ApplicationException(String.Format( _
         "The {0} publication does not exist.", publicationName))
    End If
Catch ex As Exception
    ' Implement custom application error handling here.
    Throw New ApplicationException(String.Format( _
     "A snapshot could not be generated for the {0} publication." _
     , publicationName), ex)
Finally
    conn.Disconnect()
End Try

应用初始快照时给予阻止

如果有多个发布,则在应用初始快照时,可将数据发布到订阅服务器的一个数据库中,这时你会注意到一次只有一个发布能够应用其快照。

当查看 SQL 活动时,可能会看到类似于以下内容的等待资源:

应用:18:16384:[snapshot_delivery_in_progress_Tr]:(9bcdaf92)
应用:5:16384:[snapshot_delivery_in_progress_Er]:(3c3b7db9
)

查询锁定行为时可能会显示类似于以下内容的资源:

应用 16384:[appname]:(fbe42d68) XAPP 16384:[snapshot_del]:(9bcdaf92) X

此行为是特意这样设计的。 之所以发生这种情况,是因为应用程序锁用于防止多个复制代理同时将不同发布的快照应用于同一订阅服务器数据库。 由于应用程序锁包含订阅服务器数据库的名称,因此发布到同一订阅服务器数据库的任何发布都将受到影响。 结果是,在给定时间只能将一个快照插入到订阅服务器数据库中。

在这种情况下,使用排他锁来帮助避免复制代理彼此之间出现死锁现象的可能性。

要解决此问题,请为每个发布指定不同的订阅服务器数据库。