【问题标题】:Exclusive access could not be obtained because the database is in use无法获得独占访问,因为数据库正在使用中
【发布时间】:2011-05-02 02:16:59
【问题描述】:

我正在使用以下代码来恢复数据库,

void Restore(string ConnectionString, string DatabaseFullPath, string backUpPath)
{
    string sRestore =
        "USE [master] RESTORE DATABASE [" + DatabaseFullPath + "] FROM DISK = N'" + backUpPath + "' WITH  FILE = 1,  NOUNLOAD,  STATS = 10";

    using (SqlConnection con = new SqlConnection(ConnectionString))
    {
        con.Open();
        SqlCommand cmdBackUp = new SqlCommand(sRestore, con);
        cmdBackUp.ExecuteNonQuery();
    }
}

但我收到以下异常

"Exclusive access could not be obtained because the database is in use.
RESTORE DATABASE is terminating abnormally.
Changed database context to 'master'."

我该如何解决?

【问题讨论】:

    标签: c# sql tsql database-restore


    【解决方案1】:

    只有当数据库没有任何连接(除了你的)时,才能进行还原。在 MS SQL Server 上启动所有用户的简单方法是:

    ALTER DATABASE [MyDB] SET Single_User WITH Rollback Immediate
    GO
    

    现在,您可以毫无顾忌地执行恢复了。完成还原后,请确保将其设置回多用户模式:

    ALTER DATABASE [MyDB] SET Multi_User
    GO
    

    【讨论】:

    • 我的数据库位于D:\SQL\RRDB.mdf,我必须将MyDB 替换为完整路径还是只替换RRDB.mdf
    • 我已经创建了数据库 Single_user,但我遇到了同样的问题!
    • 你必须把“With Rollback Immediate”放在语句的末尾;在断开连接时立即回滚所有待处理的事务。只需将其设置为单个用户,默认情况下将保持连接打开,直到事务完成。
    • 对我不起作用。我收到同样的错误“无法获得独占访问权限...”
    【解决方案2】:

    因此我编写了以下方法来恢复我的数据库,
    我走对了吗?

    void Restore(string ConnectionString, string DatabaseFullPath, string backUpPath)
    {
        using (SqlConnection con = new SqlConnection(ConnectionString))
        {
            con.Open();
    
            string UseMaster = "USE master";
            SqlCommand UseMasterCommand = new SqlCommand(UseMaster, con);
            UseMasterCommand.ExecuteNonQuery();
    
            string Alter1 = @"ALTER DATABASE [" + DatabaseFullPath + "] SET Single_User WITH Rollback Immediate";
            SqlCommand Alter1Cmd = new SqlCommand(Alter1, con);
            Alter1Cmd.ExecuteNonQuery();
    
            string Restore = @"RESTORE DATABASE [" + DatabaseFullPath + "] FROM DISK = N'" + backUpPath + @"' WITH  FILE = 1,  NOUNLOAD,  STATS = 10";
            SqlCommand RestoreCmd = new SqlCommand(Restore, con);
            RestoreCmd.ExecuteNonQuery();
    
            string Alter2 = @"ALTER DATABASE [" + DatabaseFullPath + "] SET Multi_User";
            SqlCommand Alter2Cmd = new SqlCommand(Alter2, con);
            Alter2Cmd.ExecuteNonQuery();
    
            labelReport.Text = "Successful";
        }
    }
    

    【讨论】:

    • 对我来说看起来不错,原则上。我无法运行它,但没有明显的错误。请记住,“立即回滚设置单个用户”将关闭所有连接(运行命令的连接除外)并回滚所有事务。
    【解决方案3】:

    最好的方法

    Alter Database <Db_Name>  SET [SINGLE_USER | RESTRICTED_USER] 
    With ROLLBACK [IMMEDIATE | AFTER 30]
    go
    --do your job that needs exclusive access
    go
    --Back to normal mode
    Alter Database <Db_Name> SET MULTI_USER 
    
    • 立即回滚 - 此选项不等待交易 完成它只是开始回滚所有打开的事务
    • 在 nnn 之后回滚 - 此选项将回滚所有打开的 交易等待 nnn 秒后开放交易 完全的。在我们的示例中,我们指定流程应该 在回滚任何打开的事务之前等待 30 秒。

    • RESTRICTED_USER 被指定时,只有 db_owner 的成员, dbcreator 或 sysadmin 角色可以使用数据库。 MULTI_USER 返回 数据库恢复到正常运行状态。


    第二种方式:使用 ssms 2008 R2 我们可以做同样的事情

    1. 右键单击数据库属性
    2. 转到选项 -> 带有 state 标题的最后一部分
    3. 限制访问更改为SINGLE_USER
    4. 对这个有用的问题回答是,这表明这种操作将关闭所有其他连接,我想这是我们在这里寻找的唯一绕过错误的方法

    要更改数据库属性,SQL Server 必须关闭与数据库的所有其他连接。您确定要更改属性并关闭所有其他连接吗?是或否

    1. 恢复您的数据库
    2. 执行步骤 1-4,将 限制访问 改回 MULTI_USER

    第三种方式:以下命令也将关闭所有连接。

    ALTER DATABASE [DbName] SET OFFLINE
    go    
    ALTER DATABASE [DbName] SET ONLINE
    

    现在数据库已准备好恢复

    更多 (mssqltips :Getting exclusive access to restore SQL Server databases)

    【讨论】:

    • SET OFFLINE & SET ONLINE 也适用于 SQL 2008。请注意,两者必须连续进行;如果数据库处于脱机状态,则无法恢复。
    • 如果数据库离线,可以恢复。我在更新的 2008 R2 上对其进行了测试,它工作正常。通常上述方法不起作用,您必须使用活动监视器来终止活动会话。
    【解决方案4】:

    您可以使用 SMO SqlServer 对象上的方法在执行还原之前终止指定数据库上的所有进程:

    sqlServer.KillAllProcesses("databaseName");
    

    【讨论】:

      【解决方案5】:

      这个问题的原因是不言而喻的(与当前打开/活动的数据库的连接),但使用以下方法(谷歌也可以理解),它会没事的:

      Alter Database YOURDB   
      SET SINGLE_USER With ROLLBACK IMMEDIATE
      GO
      

      显然,将YOURDDB 替换为您的数据库名称,然后针对主数据库运行该名称。

      哦,只是以防万一,如果您在单用户模式下“卡住”了,这将撤消它:

      Alter Database YOURDB   
      SET MULTI_USER With ROLLBACK IMMEDIATE
      GO
      

      希望这会有所帮助。

      编辑:

      您也可以关注this,查看连接来自哪里,以及其他信息:

      我在使用服务时对此进行了测试 运行将重新连接到 数据库。我发现你必须设置为 单用户模式,然后运行 ​​sp_who2 到 查看一个连接在哪里 来自,并注意 SPID。你 可以为该 SPID 运行 kill 命令 和相同的恢复 交易,它应该通过。 这是我使用的顺序:

      使用 MASTER ALTER DATABASE DATABASENAME SET SINGLE_USER WITH ROLLBACK 马上去

      -这将使得只有一个到数据库的连接可以 制成。 - 运行以下命令以查看任何重复连接到的位置 数据库来自。

      执行 SP_WHO2

      -检查此列表,查看 DBName 列。如果数据库是 列出,检查程序名称,和 HostName 列查看谁是 试图连接。 - 如果它不是服务或其他应用程序会自动 重新连接可以关闭,注意 要杀死的 SPID 列中的数字 连接,并立即开始 备份。将下面的 SPID 替换为 只是数字。

      杀死 SPID 恢复数据库 来自磁盘的数据库名称 = 'X:\PATHTO\BACKUP.BAK' 去

      -如果成功完成,我们可以设置新恢复的数据库 返回多用户模式。

      更改数据库数据库名称集 MULTI_USER WITH ROLLBACK IMMEDIATE GO

      【讨论】:

      • -1 表示剽窃。 EDIT 下方的文字直接复制自 TheOneBlackMage 的回答 here
      • “打电话给互联网警察,我犯了一个错误,现在我正在引用网站来尝试救赎自己”
      • 1.查看编辑历史记录,您在我发表评论之后添加了超链接。 2. 知道为什么我在发表评论后立即对我的其他一些答案投了 4 票吗?
      • 剽窃(来自 WIKIPEDIA):“对另一位作者的语言、思想、想法或表达方式的不正当挪用、密切模仿或盗用和发表,并将其表示为自己的原创作品。 "
      【解决方案6】:
      • 只能建立一个到数据库的连接。 - 运行以下命令以查看与数据库的任何重复连接来自何处。

        EXEC SP_WHO2
        
      • 检查此列表,查看 DBName 列下方。如果列出了数据库,请检查 ProgramName 和 HostName 列以查看谁在尝试连接。

      • 如果不是服务或其他会自动重新连接且可以关闭的应用程序,请记下 SPID 列中的数字以终止连接,然后立即开始备份。仅将下面的 SPID 替换为数字。

        KILL SPID RESTORE DATABASE DATABASENAME FROM DISK = 'X:\PATHTO\BACKUP.BAK' GO
        
      • 如果成功完成,我们可以将新恢复的数据库设置回多用户模式。

        ALTER DATABASE DATABASENAME SET MULTI_USER WITH ROLLBACK IMMEDIATE GO
        

      【讨论】:

        猜你喜欢
        • 2014-04-08
        • 1970-01-01
        • 2020-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-05
        相关资源
        最近更新 更多