【问题标题】:How to reliably overwrite existing database using Powershell Restore-SqlDatabase cmdlet如何使用 Powershell Restore-SqlDatabase cmdlet 可靠地覆盖现有数据库
【发布时间】:2015-04-27 06:44:35
【问题描述】:

我得到了这个 cmdlet 来恢复数据库,如果没有使用现有数据库,它可以正常工作。

Restore-SqlDatabase -ServerInstance $databaseServerInstance -Database $database -BackupFile $backupLocation -ReplaceDatabase

但是当数据库正在使用时覆盖失败:

System.Data.SqlClient.SqlError:无法获得独占访问 因为数据库正在使用中

我不知道是否有一种简单的方法(通过参数)来覆盖它并终止连接或将数据库置于单用户模式。有这样的事吗?还是我必须切换到 SMO 才能执行比基本还原更复杂的操作?

我现在正在使用一种解决方法,即首先使用 SMO API 删除数据库,但如果可能的话,我希望能简化它。

$srv = new-object Microsoft.SqlServer.Management.Smo.Server($databaseServerInstance)

# If the database exists then drop it otherwise Restore-SqlDatabase may fail if connections are open to it
if ($srv.Databases[$database] -ne $null)
{
    $srv.KillAllProcesses($database)
    $srv.KillDatabase($database)
}


Restore-SqlDatabase -ServerInstance $databaseServerInstance -Database $database -BackupFile $backupLocation -ReplaceDatabase

【问题讨论】:

  • 感谢方便的 PS :) 帮助!

标签: sql powershell sql-server-2012


【解决方案1】:

我正在为此使用 Invoke-SqlCmd。 Invoke-SqlCmd是sqlps模块的一部分,可以从here下载:

Push-Location; 
Import-Module sqlps -DisableNameChecking; 
Pop-Location

$serverPath = "SQLSERVER:\SQL\localhost\Default"
$databaseName = "YOUR_DATABASE"
$restoreFrom = join-path (Get-Location) "$databaseName-before.bak"

$databasePath = join-path $serverPath "Databases\$databaseName"
if(Test-Path $databasePath)
{
    Invoke-SqlCmd "USE [master]; ALTER DATABASE [$databaseName] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$databaseName]"
}

Restore-SqlDatabase -Path $serverPath -Database $databaseName -BackupFile $restoreFrom

您可以在此处找到有关如何使用 Invoke-SqlCmd 的更多信息:

Effectively Using Invoke-SqlCmd

SQL SERVER – FIX – The term ‘Invoke-Sqlcmd’ is not recognized as the name of a cmdlet

【讨论】:

    【解决方案2】:

    Restore-SqlDatabase 中没有参数可以杀死所有使用您要恢复的数据库的进程。

    您可以执行以下脚本以获取 Restore-SqlDatabase 中参数的完整文档

    get-help Restore-SqlDatabase -full
    

    【讨论】:

      【解决方案3】:

      多年后,我遇到了同样的问题,但想留在 SMO。解决方案是使用 MS 页面 here 上记录的 TerminationClause Enum。 终止枚举用于以下行:

      $db.alter(1)
      

      并使用任一:

      0 --> (default) FailOnOpenTransactions
      1 --> RollbackTransactionsImmediately
      

      完整的解决方案如下所示:

      $Instance = 'localhost'
      $dbName = 'DB_I_Want_To_Restore'
      
      $server = New-Object ('Microsoft.SqlServer.Management.Smo.Server') ($Instance)
      $db = $server.Databases | ? {$_.Name -eq $dbName}
      
      $db.useraccess = 'Single'
      $server.KillAllProcesses($db)
      $db.alter(1)                                      
      
      Restore-SqlDatabase -ServerInstance $Instance -Database $dbName -BackupFile 'location_of_your_backup_file'
      

      【讨论】:

        【解决方案4】:

        将数据库设置为single user mode 并回滚任何现有事务。这是通过像这样的 Tsql 语句完成的,

        ALTER DATABASE MyDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
        

        既然您已经在使用它,为什么不在还原之前删除数据库?

        USE master; -- or some other db than the one you are going to drop
        DROP DATABASE MyDatabase;
        

        另一种方法是使用WITH REPLACE 选项来restore the database

        【讨论】:

        • 我正在寻找不涉及 SQL 脚本的 Powershell 解决方案。我已经有一个可以工作但它需要删除 DB - 请参阅我上面的问题。但我认为只有“Restore-SqlDatabase”cmdlet 可以使用一些我不关心的标志。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-30
        • 1970-01-01
        • 1970-01-01
        • 2015-07-08
        • 1970-01-01
        相关资源
        最近更新 更多