代码之家  ›  专栏  ›  技术社区  ›  Chuck Russell

当.bak文件中有多个备份点时,使用SMO Restore Class

  •  6
  • Chuck Russell  · 技术社区  · 10 年前

    我正在尝试使用SMO编写一个简单的实用程序来备份/还原数据库。当备份文件中只有一个时间点时,这非常有效。但是,当存在定义了多个备份点(而不是备份集)的备份文件时,SMO总是选择最早的,而SSMS总是选择最新的。

    这会导致数据的错误还原,我想弄清楚是否有一个属性可以设置,该属性将强制restore类始终使用最新的备份点。

    我已经尝试过设置Restore.ToPointInTime,但由于数据库的恢复模型很简单,因此无法工作。

    我找到了一篇MSDN文章,描述了如何选择恢复时间,其中包括将数据库设置为完全恢复模式:

    http://technet.microsoft.com/en-us/library/ms179451(v=sql.105).aspx

    在使用SMO时,这是必要的吗?有没有一种方法可以使用纯SMO(没有C#sql命令)?我使用了Restore.ReadBackupHeaders,从中我可以及时提取可用的备份点,但无法将其设置为在任何位置进行恢复。

    编辑:

    下面是我正在使用的代码,包括最近的一个更改,它试图通过smo设置数据库恢复模型:

        public void RestoreDatabase(string databaseName, string backupPath)
        {
            var server = new Server(GetServerConnection());
    
            //If the database doesn't exist, create it so that we have something
            //to overwrite.
            if (!server.Databases.Contains(databaseName))
            {
                var database = new Database(server, databaseName);
                database.Create();
            }
    
            var targetDatabase = server.Databases[databaseName];
            targetDatabase.RecoveryModel = RecoveryModel.Full;
            targetDatabase.Alter();
    
            Restore restore = new Restore();
    
            var backupDeviceItem = new BackupDeviceItem(backupPath, DeviceType.File);
            restore.Devices.Add(backupDeviceItem);
            restore.Database = databaseName;
            restore.ReplaceDatabase = true;
            restore.Action = RestoreActionType.Database;
    
            var fileList = restore.ReadFileList(server);
    
            var dataFile = new RelocateFile();
            string mdf = fileList.Rows[0][1].ToString();
            dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
            dataFile.PhysicalFileName = server.Databases[databaseName].FileGroups[0].Files[0].FileName;
    
            var logFile = new RelocateFile();
            string ldf = fileList.Rows[1][1].ToString();
            logFile.LogicalFileName = fileList.Rows[1][0].ToString();
            logFile.PhysicalFileName = server.Databases[databaseName].LogFiles[0].FileName;
    
            restore.RelocateFiles.Add(dataFile);
            restore.RelocateFiles.Add(logFile);
    
            var backupHeaderInfo = GetBackupHeaderInformation(restore, server);
            var latestBackupDate = backupHeaderInfo.Max(backupInfo => backupInfo.BackupStartDate);
    
            restore.ToPointInTime = latestBackupDate.ToString();
    
            server.KillAllProcesses(databaseName);
    
            restore.SqlRestore(server);
        }
    

    看起来这应该能起到作用,然而

    targetDatabase.RecoveryModel = RecoveryModel.Full
    

    似乎没有采取任何措施来改变恢复模式,导致我仍然遇到以下异常:

    使用SIMPLE恢复模型的数据库不支持STOPAT选项。 RESTORE DATABASE异常终止。

    编辑2:

    我添加了该行

    targetDatabase.Alter();
    

    并解决了不更新的问题。但是,它现在恢复,但使数据库处于恢复模式,因此无法查询。

    编辑3:

    我通过将Restore.FileNumber属性设置为BackupHeaders中位置的最大值来使代码正常工作,这似乎很有用,尽管我仍然不确定为什么备份文件有多个备份头,但只有一个备份集。

    工作代码如下。

        public void RestoreDatabase(string databaseName, string backupPath)
        {
            var server = new Server(GetServerConnection());
    
            //If the database doesn't exist, create it so that we have something
            //to overwrite.
            if (!server.Databases.Contains(databaseName))
            {
                var database = new Database(server, databaseName);
                database.Create();
            }
    
            var targetDatabase = server.Databases[databaseName];
            targetDatabase.RecoveryModel = RecoveryModel.Full;
            targetDatabase.Alter();
    
            Restore restore = new Restore();
    
            var backupDeviceItem = new BackupDeviceItem(backupPath, DeviceType.File);
            restore.Devices.Add(backupDeviceItem);
            restore.Database = databaseName;
            restore.ReplaceDatabase = true;
            restore.NoRecovery = false;
            restore.Action = RestoreActionType.Database;
    
            var fileList = restore.ReadFileList(server);
    
            var dataFile = new RelocateFile();
            dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
            dataFile.PhysicalFileName = server.Databases[databaseName].FileGroups[0].Files[0].FileName;
    
            var logFile = new RelocateFile();
            logFile.LogicalFileName = fileList.Rows[1][0].ToString();
            logFile.PhysicalFileName = server.Databases[databaseName].LogFiles[0].FileName;
    
            restore.RelocateFiles.Add(dataFile);
            restore.RelocateFiles.Add(logFile);
    
            var backupHeaderInfo = GetBackupHeaderInformation(restore, server);
            restore.FileNumber = backupHeaderInfo.Where(backupInfo => backupInfo.BackupType == BackupType.Database).Max(backupInfo => backupInfo.Position);
    
            server.KillAllProcesses(databaseName);
    
            restore.SqlRestore(server);
    
            targetDatabase.SetOnline();
        }
    
    1 回复  |  直到 10 年前
        1
  •  5
  •   Ben Thul    10 年前

    尽管你说你没有多个备份集,但我认为你有

    备份集包含单个成功备份操作的备份。

    因此,如果在一个备份文件中有“多个还原点”,则有多个备份集。通过查询msdb中的dbo.backup表来验证这一点

    撇开教学不谈,我认为您正在查找Restore对象上的FileNumber属性。这对应于 FILE = n T-SQL restore命令中的备份集选项。为了获得最后一行,只需从ReadBackupHeaders调用中提取最后一行。

    要自己测试,请通过SSMS执行恢复操作,然后单击顶部附近的“脚本”按钮,而不是单击“确定”。我想你会看到 FILE = <some number> 在那里的某个地方。