Partager via


Procédure : sauvegarder et restaurer une base de données (SQL Server)

Cette rubrique décrit comment sauvegarder et restaurer une base de données SQL Server synchronisée à l'aide de Sync Framework. Le code dans cette application est axé sur les classes Sync Framework suivantes :

Pour plus d'informations sur le mode d'exécution d'un exemple de code, consultez « Exemples d'application dans les rubriques de procédures » dans Synchronisation de SQL Server et SQL Server Compact.

Présentation de la sauvegarde et de la restauration pour les bases de données synchronisées

Une base de données serveur qui intervient dans la synchronisation doit être sauvegardée régulièrement, comme n'importe quelle autre base de données de production. Si vous restaurez une base de données à partir d'une sauvegarde, Sync Framework doit mettre à jour les métadonnées de synchronisation pour résoudre les problèmes liés aux modifications qui peuvent se produire après que la sauvegarde a été effectuée. Les modifications sont classées dans trois catégories :

  • La modification a été apportée au niveau d'un client ou d'un autre serveur homologue.

    Une fois le serveur restauré, la synchronisation avec d'autres nœuds mettra finalement le serveur à jour avec ces modifications distantes.

  • La modification a été apportée au niveau du serveur et elle a été propagée à au moins un client ou serveur homologue.

    Une fois le serveur restauré, la synchronisation avec d'autres nœuds mettra finalement le serveur à jour avec ces modifications locales qui n'ont pas été incluses dans la sauvegarde. Les métadonnées sont mises à jour pour gérer correctement cette situation.

  • La modification a été apportée au niveau du serveur, mais elle n'a pas été propagée à des clients ou serveurs homologues.

    Comme dans d'autres cas dans lesquels une modification ne fait pas partie d'une sauvegarde, les modifications de ce type ne peuvent pas être restaurées.

Mise à jour des métadonnées après la restauration d'un serveur

Pour chaque modification qui se produit dans une table, Sync Framework met à jour des métadonnées sur le serveur pour identifier l'heure et l'origine de la modification. Ces métadonnées sont utilisées par d'autres nœuds pour déterminer les lignes que chaque nœud requiert du serveur. Si des modifications se produisent au niveau du serveur après une sauvegarde et que ces modifications sont propagées à d'autres nœuds avant une restauration, les autres nœuds contiendront des métadonnées pour chacune des lignes modifiées. Après avoir restauré le serveur de la sauvegarde, des identificateurs qui entrent en collision avec ceux que les autres nœuds contiennent déjà peuvent être attribués à des modifications ultérieures sur le serveur. Cela peut provoquer des conflits pendant la synchronisation et une non-convergence possible.

Pour éviter ces problèmes, Sync Framework attribue un nouvel ID de réplica au serveur et met à jour plusieurs colonnes de métadonnées pour chaque table synchronisée.

Pour restaurer le serveur et mettre à jour les métadonnées

  1. Établissez un accès exclusif à la base de données serveur. Cela empêche toutes les opérations locales ou de synchronisation de mettre à jour des données ou des métadonnées jusqu'à ce que la base de données soit prête.

  2. Restaurez la base de données SQL Server à partir d'une sauvegarde complète, et toutes les sauvegardes différentielles, le cas échéant.

  3. Exécutez PerformPostRestoreFixup.

  4. Activez l'accès total à la base de données. À ce stade, des modifications locales peuvent se produire sur le serveur, et les clients et d'autres serveurs homologues peuvent être synchronisés avec le serveur.

Exemples

L'exemple de code suivant effectue une sauvegarde de la base de données serveur et apporte des modifications dans la base de données en appelant des méthodes dans l'exemple de classe Utility, puis synchronise ces modifications.

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

L'application appelle une procédure stockée (usp_SampleDbBackupRestore) qui contient le code Transact-SQL suivant pour sauvegarder la base de données serveur.

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

La même procédure contient également le code Transact-SQL pour restaurer la base de données serveur.

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

L'exemple de code suivant restaure la base de données serveur et appelle PerformPostRestoreFixup() pour mettre à jour les métadonnées. L'application synchronise ensuite une nouvelle fois tous les nœuds.

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

Exemple de code complet

L'exemple de code complet ci-dessous inclut les exemples de code décrits précédemment, ainsi que du code supplémentaire. L'exemple requiert la classe Utility qui est disponible dans Classe d'utilitaire pour les rubriques de procédures sur le fournisseur de bases de données.

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

Voir aussi

Concepts

Synchronisation de SQL Server et SQL Server Compact