共用方式為


HOW TO:備份和還原資料庫 (SQL Server)

本主題描述如何備份和還原使用 Sync Framework 同步處理的 SQL Server 資料庫。此應用程式中的程式碼著重於下列 Sync Framework 類別:

如需如何執行範例程式碼的詳細資訊,請參閱同步處理 SQL Server 和 SQL Server Compact 中的<HOW-TO 主題中的範例應用程式>。

了解已同步處理之資料庫的備份和還原

和所有實際執行的資料庫一樣,需要同步處理的伺服器資料庫也應該定期進行備份。如果您是從備份還原資料庫,Sync Framework 就必須更新同步處理中繼資料,以便處理進行備份之後可能會發生的變更問題。這些變更可分成三個類別:

  • 在用戶端或其他對等伺服器上進行變更。

    還原伺服器之後,與其他節點同步處理最後都會使用這些遠端變更,讓伺服器處於最新狀態。

  • 在伺服器上進行變更,而且此變更至少傳播至一個用戶端或對等伺服器。

    還原伺服器之後,與其他節點同步處理最後都會使用備份沒有包含的這些本機變更,讓伺服器處於最新狀態。系統會更新中繼資料,以便適當地處理此案例。

  • 在伺服器上進行變更,不過此變更沒有傳播至任何用戶端或對等伺服器。

    如同變更不屬於備份一部分的其他情況,這種類型的變更無法還原。

在還原伺服器之後更新中繼資料

對於在資料表中進行的每一項變更,Sync Framework 都會更新伺服器上的中繼資料,以便識別變更的時間和來源。其他節點會使用這個中繼資料來判斷每個節點需要向伺服器取得的資料列。如果在備份之後於伺服器上進行變更,而且在還原之前將這些變更傳播至其他節點,其他節點將會包含每個已變更資料列的中繼資料。從備份還原伺服器之後,伺服器上後續變更被指派的識別碼可能會與其他節點已經包含的識別碼發生衝突。這可能會在同步處理期間導致衝突,甚至可能發生無法聚合的情況。

為了避免這些問題,Sync Framework 會指派新的複寫識別碼給伺服器,並且針對已同步處理的每個資料表更新許多中繼資料資料行。

若要還原伺服器並更新中繼資料

  1. 建立伺服器資料庫的獨佔存取權。這樣做可防止任何本機作業或同步處理作業在資料庫就緒之前更新資料或中繼資料。

  2. 從完整備份以及任何差異備份 (如果適用的話) 還原 SQL Server 資料庫。

  3. 執行 PerformPostRestoreFixup

  4. 啟用資料庫的完整存取權。此時,本機變更就可以在伺服器上進行,而且用戶端和其他對等伺服器可以與伺服器同步處理。

範例

下列程式碼範例會透過呼叫範例 Utility 類別中的方法,執行伺服器資料庫的備份並在資料庫中進行變更,然後同步處理這些變更。

// Backup the server database.         
Utility.CreateDatabaseBackup();

// Make changes on the server: 1 insert, 1 update, and 1 delete.
Utility.MakeDataChangesOnNode(Utility.ConnStr_SqlSync_Server, "Customer");                            

// Synchronize the three changes.
syncOrchestrator = new SampleSyncOrchestrator(
    new SqlCeSyncProvider("customer", clientSqlCe1Conn),
    new SqlSyncProvider("customer", serverConn)
    );
syncStats = syncOrchestrator.Synchronize();
syncOrchestrator.DisplayStats(syncStats, "subsequent");
' Backup the server database. 
Utility.CreateDatabaseBackup()

' Make changes on the server: 1 insert, 1 update, and 1 delete. 
Utility.MakeDataChangesOnNode(Utility.ConnStr_SqlSync_Server, "Customer")

' Synchronize the three changes. 
syncOrchestrator = New SampleSyncOrchestrator( _
    New SqlCeSyncProvider("customer", clientSqlCe1Conn), _
    New SqlSyncProvider("customer", serverConn))
syncStats = syncOrchestrator.Synchronize()
syncOrchestrator.DisplayStats(syncStats, "subsequent")

此應用程式會呼叫包含下列 Transact-SQL 程式碼的預存程序 (usp_SampleDbBackupRestore) 來備份伺服器資料庫。

BACKUP DATABASE [SyncSamplesDb_SqlPeer1] 
TO  DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\SyncSamplesDb_SqlPeer1.bak' 
WITH NOFORMAT, NOINIT,  NAME = N'SyncSamplesDb_SqlPeer1-Full Database Backup', SKIP, NOREWIND, NOUNLOAD,  STATS = 10

相同的程序也會包含還原伺服器資料庫的 Transact-SQL 程式碼。

-- Backup the tail of the log.
BACKUP LOG [SyncSamplesDb_SqlPeer1] 
TO  DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\SyncSamplesDb_SqlPeer1.bak' 
WITH  NO_TRUNCATE , NOFORMAT, NOINIT,  NAME = N'TestBackupRestore-Transaction Log  Backup', SKIP, NOREWIND, NOUNLOAD,  NORECOVERY ,  STATS = 10

-- Restore the database.
RESTORE DATABASE [SyncSamplesDb_SqlPeer1] 
FROM  DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\SyncSamplesDb_SqlPeer1.bak' 
WITH FILE = 1,  NOUNLOAD,  STATS = 10

下列程式碼範例會還原伺服器資料庫並呼叫 PerformPostRestoreFixup() 來更新中繼資料。然後,此應用程式會再次同步處理所有節點。

Utility.RestoreDatabaseFromBackup();


// Call the API to update synchronization metadata to reflect that the database was
// just restored. The restore stored procedure kills the connection to the
// server, so we must re-establish it.
SqlConnection.ClearPool(serverConn);
serverConn = new SqlConnection(Utility.ConnStr_SqlSync_Server);
SqlSyncStoreRestore databaseRestore = new SqlSyncStoreRestore(serverConn);
databaseRestore.PerformPostRestoreFixup();
Utility.RestoreDatabaseFromBackup()


' Call the API to update synchronization metadata to reflect that the database was 
' just restored. The restore stored procedure kills the connection to the 
' server, so we must re-establish it. 
SqlConnection.ClearPool(serverConn)
serverConn = New SqlConnection(Utility.ConnStr_SqlSync_Server)
Dim databaseRestore As New SqlSyncStoreRestore(serverConn)
databaseRestore.PerformPostRestoreFixup()

完整的程式碼範例

下列完整的程式碼範例包含先前所述的程式碼範例,以及其他的程式碼。此範例需要 Utility 類別,詳情請參閱資料庫提供者公用程式類別的 HOW-TO 主題

// NOTE: Before running this application, run the database sample script that is
// available in the documentation. The script drops and re-creates the tables that 
// are used in the code, and ensures that synchronization objects are dropped so that 
// Sync Framework can re-create them.

using System;
using System.IO;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlServerCe;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
using Microsoft.Synchronization.Data.SqlServerCe;

namespace Microsoft.Samples.Synchronization
{
    class Program
    {
        static void Main(string[] args)
        {

            // Create the connections over which provisioning and synchronization
            // are performed. The Utility class handles all functionality that is not
            //directly related to synchronization, such as holding connection 
            //string information and making changes to the server database.
            SqlConnection serverConn = new SqlConnection(Utility.ConnStr_SqlSync_Server);
            SqlConnection clientSqlConn = new SqlConnection(Utility.ConnStr_SqlSync_Client);
            SqlCeConnection clientSqlCe1Conn = new SqlCeConnection(Utility.ConnStr_SqlCeSync1);

            // Create a scope named "customer", and add the Customer table to the scope.
            // GetDescriptionForTable gets the schema of the table, so that tracking 
            // tables and triggers can be created for that table.
            DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription("customer");

            scopeDesc.Tables.Add(
            SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", serverConn));

            // Create a provisioning object for "customer" and specify that
            // base tables should not be created (They already exist in SyncSamplesDb_SqlPeer1).
            SqlSyncScopeProvisioning serverConfig = new SqlSyncScopeProvisioning(scopeDesc);
            serverConfig.SetCreateTableDefault(DbSyncCreationOption.Skip);

            // Configure the scope and change-tracking infrastructure.
            serverConfig.Apply(serverConn);

            // Retrieve scope information from the server and use the schema that is retrieved
            // to provision the SQL Server and SQL Server Compact client databases.           

            // This database already exists on the server.
            DbSyncScopeDescription clientSqlDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope("customer", serverConn);
            SqlSyncScopeProvisioning clientSqlConfig = new SqlSyncScopeProvisioning(clientSqlDesc);
            clientSqlConfig.Apply(clientSqlConn);

            // This database does not yet exist.
            Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, true);
            DbSyncScopeDescription clientSqlCeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope("customer", serverConn);
            SqlCeSyncScopeProvisioning clientSqlCeConfig = new SqlCeSyncScopeProvisioning(clientSqlCeDesc);
            clientSqlCeConfig.Apply(clientSqlCe1Conn);


            // Initial synchronization sessions.
            SampleSyncOrchestrator syncOrchestrator;
            SyncOperationStatistics syncStats;

            // Data is downloaded from the server to the SQL Server client.
            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlSyncProvider("customer", clientSqlConn),
                new SqlSyncProvider("customer", serverConn)
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "initial");

            // Data is downloaded from the SQL Server client to the 
            // SQL Server Compact client.
            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlCeSyncProvider("customer", clientSqlCe1Conn),
                new SqlSyncProvider("customer", clientSqlConn)
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "initial");


            // Remove the backup file because this application requires a drop and recreation
            // of the sample database, and the backup must be recreated each time
            // the application runs.
            Utility.DeleteDatabaseBackup();


            // Backup the server database.         
            Utility.CreateDatabaseBackup();

            // Make changes on the server: 1 insert, 1 update, and 1 delete.
            Utility.MakeDataChangesOnNode(Utility.ConnStr_SqlSync_Server, "Customer");                            
            
            // Synchronize the three changes.
            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlCeSyncProvider("customer", clientSqlCe1Conn),
                new SqlSyncProvider("customer", serverConn)
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "subsequent");

            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlSyncProvider("customer", clientSqlConn),
                new SqlCeSyncProvider("customer", clientSqlCe1Conn)
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "subsequent");

            // Restore the server database from backup. The restored version
            // does not contain the three changes that were just synchronized.
            Utility.RestoreDatabaseFromBackup();


            // Call the API to update synchronization metadata to reflect that the database was
            // just restored. The restore stored procedure kills the connection to the
            // server, so we must re-establish it.
            SqlConnection.ClearPool(serverConn);
            serverConn = new SqlConnection(Utility.ConnStr_SqlSync_Server);
            SqlSyncStoreRestore databaseRestore = new SqlSyncStoreRestore(serverConn);
            databaseRestore.PerformPostRestoreFixup();


            // Synchronize a final time.
            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlCeSyncProvider("customer", clientSqlCe1Conn),
                new SqlSyncProvider("customer", serverConn)
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "subsequent");

            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlSyncProvider("customer", clientSqlConn),
                new SqlCeSyncProvider("customer", clientSqlCe1Conn)
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "subsequent");

            serverConn.Close();
            serverConn.Dispose();
            clientSqlConn.Close();
            clientSqlConn.Dispose();
            clientSqlCe1Conn.Close();
            clientSqlCe1Conn.Dispose();

            Console.Write("\nPress any key to exit.");
            Console.Read();
            
        }

    }

    public class SampleSyncOrchestrator : SyncOrchestrator
    {
        public SampleSyncOrchestrator(RelationalSyncProvider localProvider, RelationalSyncProvider remoteProvider)
        {

            this.LocalProvider = localProvider;
            this.RemoteProvider = remoteProvider;
            this.Direction = SyncDirectionOrder.UploadAndDownload;
        }

        public void DisplayStats(SyncOperationStatistics syncStatistics, string syncType)
        {
            Console.WriteLine(String.Empty);
            if (syncType == "initial")
            {
                Console.WriteLine("****** Initial Synchronization ******");
            }
            else if (syncType == "subsequent")
            {
                Console.WriteLine("***** Subsequent Synchronization ****");
            }

            Console.WriteLine("Start Time: " + syncStatistics.SyncStartTime);
            Console.WriteLine("Total Changes Uploaded: " + syncStatistics.UploadChangesTotal);
            Console.WriteLine("Total Changes Downloaded: " + syncStatistics.DownloadChangesTotal);
            Console.WriteLine("Complete Time: " + syncStatistics.SyncEndTime);
            Console.WriteLine(String.Empty);
        }
    }
}
' NOTE: Before running this application, run the database sample script that is
' available in the documentation. The script drops and re-creates the tables that 
' are used in the code, and ensures that synchronization objects are dropped so that 
' Sync Framework can re-create them.

Imports System
Imports System.IO
Imports System.Text
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlServerCe
Imports Microsoft.Synchronization
Imports Microsoft.Synchronization.Data
Imports Microsoft.Synchronization.Data.SqlServer
Imports Microsoft.Synchronization.Data.SqlServerCe

Namespace Microsoft.Samples.Synchronization

    Class Program

        Public Shared Sub Main(ByVal args As String())

            ' Create the connections over which provisioning and synchronization 
            ' are performed. The Utility class handles all functionality that is not 
            'directly related to synchronization, such as holding connection 
            'string information and making changes to the server database. 
            Dim serverConn As New SqlConnection(Utility.ConnStr_SqlSync_Server)
            Dim clientSqlConn As New SqlConnection(Utility.ConnStr_SqlSync_Client)
            Dim clientSqlCe1Conn As New SqlCeConnection(Utility.ConnStr_SqlCeSync1)

            ' Create a scope named "customer", and add the Customer table to the scope. 
            ' GetDescriptionForTable gets the schema of the table, so that tracking 
            ' tables and triggers can be created for that table. 
            Dim scopeDesc As New DbSyncScopeDescription("customer")

            scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", serverConn))

            ' Create a provisioning object for "customer" and specify that 
            ' base tables should not be created (They already exist in SyncSamplesDb_SqlPeer1). 
            Dim serverConfig As New SqlSyncScopeProvisioning(scopeDesc)
            serverConfig.SetCreateTableDefault(DbSyncCreationOption.Skip)

            ' Configure the scope and change-tracking infrastructure. 
            serverConfig.Apply(serverConn)

            ' Retrieve scope information from the server and use the schema that is retrieved 
            ' to provision the SQL Server and SQL Server Compact client databases. 

            ' This database already exists on the server. 
            Dim clientSqlDesc As DbSyncScopeDescription = SqlSyncDescriptionBuilder.GetDescriptionForScope("customer", serverConn)
            Dim clientSqlConfig As New SqlSyncScopeProvisioning(clientSqlDesc)
            clientSqlConfig.Apply(clientSqlConn)

            ' This database does not yet exist. 
            Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, True)
            Dim clientSqlCeDesc As DbSyncScopeDescription = SqlSyncDescriptionBuilder.GetDescriptionForScope("customer", serverConn)
            Dim clientSqlCeConfig As New SqlCeSyncScopeProvisioning(clientSqlCeDesc)
            clientSqlCeConfig.Apply(clientSqlCe1Conn)


            ' Initial synchronization sessions. 
            Dim syncOrchestrator As SampleSyncOrchestrator
            Dim syncStats As SyncOperationStatistics

            ' Data is downloaded from the server to the SQL Server client. 
            syncOrchestrator = New SampleSyncOrchestrator( _
                New SqlSyncProvider("customer", clientSqlConn), _
                New SqlSyncProvider("customer", serverConn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "initial")

            ' Data is downloaded from the SQL Server client to the 
            ' SQL Server Compact client. 
            syncOrchestrator = New SampleSyncOrchestrator( _
                New SqlCeSyncProvider("customer", clientSqlCe1Conn), _
                New SqlSyncProvider("customer", clientSqlConn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "initial")

            ' Remove the backup file because this application requires a drop and recreation 
            ' of the sample database, and the backup must be recreated each time 
            ' the application runs. 
            Utility.DeleteDatabaseBackup()

            ' Backup the server database. 
            Utility.CreateDatabaseBackup()

            ' Make changes on the server: 1 insert, 1 update, and 1 delete. 
            Utility.MakeDataChangesOnNode(Utility.ConnStr_SqlSync_Server, "Customer")

            ' Synchronize the three changes. 
            syncOrchestrator = New SampleSyncOrchestrator( _
                New SqlCeSyncProvider("customer", clientSqlCe1Conn), _
                New SqlSyncProvider("customer", serverConn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "subsequent")

            syncOrchestrator = New SampleSyncOrchestrator( _
                New SqlSyncProvider("customer", clientSqlConn), _
                New SqlCeSyncProvider("customer", clientSqlCe1Conn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "subsequent")

            ' Restore the server database from backup. The restored version 
            ' does not contain the three changes that were just synchronized. 
            Utility.RestoreDatabaseFromBackup()


            ' Call the API to update synchronization metadata to reflect that the database was 
            ' just restored. The restore stored procedure kills the connection to the 
            ' server, so we must re-establish it. 
            SqlConnection.ClearPool(serverConn)
            serverConn = New SqlConnection(Utility.ConnStr_SqlSync_Server)
            Dim databaseRestore As New SqlSyncStoreRestore(serverConn)
            databaseRestore.PerformPostRestoreFixup()


            ' Synchronize a final time. 
            syncOrchestrator = New SampleSyncOrchestrator( _
                New SqlCeSyncProvider("customer", clientSqlCe1Conn), _
                New SqlSyncProvider("customer", serverConn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "subsequent")

            syncOrchestrator = New SampleSyncOrchestrator( _
                New SqlSyncProvider("customer", clientSqlConn), _
                New SqlCeSyncProvider("customer", clientSqlCe1Conn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "subsequent")

            serverConn.Close()
            serverConn.Dispose()
            clientSqlConn.Close()
            clientSqlConn.Dispose()
            clientSqlCe1Conn.Close()
            clientSqlCe1Conn.Dispose()

            Console.Write(vbLf & "Press any key to exit.")

            Console.Read()
        End Sub

    End Class

    Public Class SampleSyncOrchestrator
        Inherits SyncOrchestrator
        Public Sub New(ByVal localProvider As RelationalSyncProvider, ByVal remoteProvider As RelationalSyncProvider)

            Me.LocalProvider = localProvider
            Me.RemoteProvider = remoteProvider
            Me.Direction = SyncDirectionOrder.UploadAndDownload
        End Sub

        Public Sub DisplayStats(ByVal syncStatistics As SyncOperationStatistics, ByVal syncType As String)
            Console.WriteLine([String].Empty)
            If syncType = "initial" Then
                Console.WriteLine("****** Initial Synchronization ******")
            ElseIf syncType = "subsequent" Then
                Console.WriteLine("***** Subsequent Synchronization ****")
            End If

            Console.WriteLine("Start Time: " & syncStatistics.SyncStartTime)
            Console.WriteLine("Total Changes Uploaded: " & syncStatistics.UploadChangesTotal)
            Console.WriteLine("Total Changes Downloaded: " & syncStatistics.DownloadChangesTotal)
            Console.WriteLine("Complete Time: " & syncStatistics.SyncEndTime)
            Console.WriteLine([String].Empty)
        End Sub
    End Class
End Namespace

請參閱

概念

同步處理 SQL Server 和 SQL Server Compact