Freigeben über


Vorgehensweise: Sichern und Wiederherstellen einer Datenbank (SQL Server)

In diesem Thema wird das Sichern und Wiederherstellen einer SQL Server-Datenbank beschrieben, die mithilfe von Sync Framework synchronisiert wird. Der Code dieser Anwendung ist auf die folgenden Sync Framework-Klassen ausgerichtet:

Informationen zum Ausführen von Beispielcode finden Sie unter "Beispielanwendungen in den Themen zur Vorgehensweise" in Synchronisieren von SQL Server und SQL Server Compact.

Grundlegendes zum Sichern und Wiederherstellen von Datenbanken, die synchronisiert werden

Wie jede andere Produktionsdatenbank sollte auch eine Serverdatenbank, die an Synchronisierungen beteiligt ist, regelmäßig gesichert werden. Wenn Sie eine Datenbank aus einer Sicherung wiederherstellen, muss Sync Framework die Synchronisierungsmetadaten aktualisieren, um Änderungen zu berücksichtigen, die nach Erstellung der Sicherung aufgetreten sind. Es gibt drei Kategorien von Änderungen:

  • Die Änderung wurde auf einem Client oder auf einem anderen Server vorgenommen.

    Nach der Wiederherstellung des Servers wird der Server durch die Synchronisierung mit anderen Knoten auf den neuesten Stand dieser Remoteänderungen gebracht.

  • Die Änderung wurde auf dem Server vorgenommen und an mindestens einen Client oder Peerserver weitergegeben.

    Nach der Wiederherstellung des Servers wird der Server durch die Synchronisierung mit anderen Knoten auf den neuesten Stand der lokalen Änderungen gebracht, die nicht in der Sicherung enthalten waren. Zur ordnungsgemäßen Behandlung dieses Falls werden Metadaten aktualisiert.

  • Die Änderung wurde auf dem Server vorgenommen, jedoch nicht an Clients oder Peerserver weitergegeben.

    Änderungen dieses Typs können nicht wiederhergestellt werden. Dies ist immer dann der Fall, wenn eine Änderung nicht in der Sicherung enthalten ist.

Aktualisieren von Metadaten nach der Wiederherstellung eines Servers

Für jede Änderung, die in einer Tabelle auftritt, aktualisiert Sync Framework Metadaten auf dem Server, um Zeit und Ursprung der Änderung zu ermitteln. Diese Metadaten werden von anderen Knoten verwendet, um festzustellen, welche Zeilen jeder Knoten vom Server benötigt. Wenn Änderungen nach der Sicherung auf dem Server auftreten und diese vor der Wiederherstellung an andere Knoten weitergegeben wurden, enthalten die anderen Knoten Metadaten für jede der geänderten Zeilen. Nachdem der Server aus der Sicherung wiederhergestellt wurde, werden späteren Änderungen auf dem Server möglicherweise Bezeichner zugewiesen, die mit den bereits auf den anderen Knoten vorhandenen Bezeichnern in Konflikt stehen können. Dadurch kann es während der Synchronisierung zu Konflikten und möglicher Nichtkonvergenz kommen.

Um diese Probleme zu vermeiden, weist Sync Framework dem Server eine neue Replikat-ID zu und aktualisiert für jede synchronisierte Tabelle mehrere Metadatenspalten.

So stellen Sie den Server wieder her und aktualisieren Metadaten

  1. Stellen Sie einen exklusiven Zugriff auf die Serverdatenbank her. Dadurch wird verhindert, dass durch lokale Vorgänge oder Synchronisierungsvorgänge Daten oder Metadaten aktualisiert werden, bevor die Datenbank bereit ist.

  2. Stellen Sie die SQL Server-Datenbank aus einer vollständigen Sicherung und ggf. aus differenziellen Sicherungen wieder her.

  3. Führen Sie PerformPostRestoreFixup aus.

  4. Aktivieren Sie Vollzugriff auf die Datenbank. Zu diesem Zeitpunkt können Änderungen auf dem Server auftreten. Außerdem können Clients und andere Peerserver mit dem Server synchronisiert werden.

Beispiele

Im folgenden Codebeispiel wird eine Sicherung der Serverdatenbank durchgeführt, und durch Aufrufen von Methoden in der Utility-Beispielklasse werden Änderungen vorgenommen, die anschließend synchronisiert werden.

// 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")

Die Anwendung ruft eine gespeicherte Prozedur auf (usp_SampleDbBackupRestore), die folgenden Transact-SQL-Code zur Sicherung der Serverdatenbank enthält.

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

Die gleiche Prozedur enthält auch Transact-SQL-Code für die Wiederherstellung der Serverdatenbank.

-- 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

Im folgenden Codebeispiel wird die Serverdatenbank wiederhergestellt und PerformPostRestoreFixup() zur Aktualisierung der Metadaten aufgerufen. Anschließend synchronisiert die Anwendung alle Knoten erneut.

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()

Vollständiges Codebeispiel

Das folgende vollständige Codebeispiel enthält die Codebeispiele, die weiter oben beschrieben wurden, sowie zusätzlichen Code. Für das Beispiel ist die in 'Utility'-Klasse für Datenbankanbieter - Themen zur Vorgehensweise enthaltene Utility-Klasse erforderlich.

// 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

Siehe auch

Konzepte

Synchronisieren von SQL Server und SQL Server Compact