【问题标题】:SQL-Server: Error - Exclusive access could not be obtained because the database is in useSQL-Server: 错误 - 无法获得独占访问权限,因为数据库正在使用中
【发布时间】:2014-04-08 04:54:13
【问题描述】:

我实际上是在尝试编写一个脚本(在 Sql Server 2008 中)从一个备份文件中恢复一个数据库。我编写了以下代码,但出现错误 -

Msg 3101, Level 16, State 1, Line 3
Exclusive access could not be obtained because 
the database is in use.
Msg 3013, Level 16, State 1, Line 3
RESTORE DATABASE is terminating abnormally.

我该如何解决这个问题?

IF DB_ID('AdventureWorksDW') IS NOT NULL 
BEGIN 
RESTORE DATABASE [AdventureWorksDW] 
FILE = N'AdventureWorksDW_Data' 
FROM  
DISK = N'C:\Program Files\Microsoft SQL Server\
MSSQL10_50.SS2008\MSSQL\Backup\AdventureWorksDW.bak' 
WITH  FILE = 1, 
MOVE N'AdventureWorksDW_Data' 
TO N'C:\Program Files\Microsoft SQL Server\
MSSQL10_50.SS2008\MSSQL\DATA\AdventureWorksDW.mdf', 
MOVE N'AdventureWorksDW_Log'  
TO N'C:\Program Files\Microsoft SQL Server\
MSSQL10_50.SS2008\MSSQL\DATA\AdventureWorksDW_0.LDF', 
NOUNLOAD,  STATS = 10 
END

【问题讨论】:

  • 如果我可以让它工作,也许我可以制作一个可靠的脚本来从一个文件夹中恢复多个数据库。我在网上找不到任何可靠的代码。我的代码可能是可靠的,因为它是由 SS 自己生成的。

标签: sql sql-server sql-server-2008


【解决方案1】:

我认为您只需在尝试恢复之前将数据库设置为单用户模式,如下所示,只需确保您使用的是master

USE master
GO
ALTER DATABASE AdventureWorksDW
SET SINGLE_USER

【讨论】:

    【解决方案2】:

    我假设如果您正在恢复一个数据库,那么您并不关心该数据库上的任何现有事务。正确的?如果是这样,这应该适合你:

    USE master
    GO
    
    ALTER DATABASE AdventureWorksDW
    SET SINGLE_USER
    --This rolls back all uncommitted transactions in the db.
    WITH ROLLBACK IMMEDIATE
    GO
    
    RESTORE DATABASE AdventureWorksDW
    FROM ...
    ...
    GO
    

    现在,还有一项需要注意的事项。将数据库设置为单用户模式后,其他人可能会尝试连接到数据库。如果他们成功,您将无法继续进行还原。这是一场比赛!我的建议是同时运行所有三个语句。

    【讨论】:

    • 一个事务中的所有三个语句。
    • 每当我尝试访问 Adventureworks 数据库时,我的 SSMS 都会进入无响应模式。
    • 他实际上是指USE master,而不是USER master
    • 只需在末尾添加ALTER DATABASE [AdventureWorksDW] SET MULTI_USER 以确保数据库恢复到正常的多用户模式。
    • @gnaanaa:如果备份的数据库在备份时处于SINGLE_USER 模式,那么备份恢复时它将处于SINGLE_USER 模式。如果备份时处于MULTI_USER 模式,则恢复时将处于MULTI_USER 模式。您提出了一个很好的观点:还原完成后绝对值得检查。您还可以在备份媒体上运行RESTORE HEADERONLY 并检查IsSingleUser 或在Flags 列上进行逐位数学运算。
    【解决方案3】:

    在恢复数据库之前,使用以下脚本查找并终止所有打开的数据库连接。

    declare @sql as varchar(20), @spid as int
    
    select @spid = min(spid)  from master..sysprocesses  where dbid = db_id('<database_name>') 
    and spid != @@spid    
    
    while (@spid is not null)
    begin
        print 'Killing process ' + cast(@spid as varchar) + ' ...'
        set @sql = 'kill ' + cast(@spid as varchar)
        exec (@sql)
    
        select 
            @spid = min(spid)  
        from 
            master..sysprocesses  
        where 
            dbid = db_id('<database_name>') 
            and spid != @@spid
    end 
    
    print 'Process completed...'
    

    希望这会有所帮助...

    【讨论】:

      【解决方案4】:

      在恢复数据库之前执行这个查询:

      alter database [YourDBName] 
      set offline with rollback immediate
      

      恢复后的这个:

        alter database [YourDBName] 
        set online
      

      【讨论】:

      • 在试点应用程序连接击败我的查询的恢复和随后的 MULTI_USER 调用后,我最终通过 SINGLE_USER 切换到此方法。恢复未能获得独占访问权限,旧数据库处于 SINGLE_USER 模式。
      • 这对我有用。恢复后它会自动上线。
      • 这行得通,它避免了接受答案中的竞争条件。
      • 谢谢安德烈。
      【解决方案5】:
      1. 设置恢复文件的路径。
      2. 点击左侧的“选项”。
      3. 取消选中“还原前进行尾日志备份”
      4. 勾选复选框 - “关闭与目标数据库的现有连接”。
      5. 点击确定。

      【讨论】:

      • 在我的情况下,该复选框是灰色的。但是,我重新开始并能够在选择要恢复的源之前选中该框。选择备份文件后,该选项再次变灰,但该框仍处于选中状态并且恢复工作正常。
      • 感谢您让我免于输入 SQL。所有答案中唯一的 GUI 方法。
      • 我希望这对我和其他人一样有用。但对我来说,复选框始终是灰色的。 Andrei Karchueuski'sanswer below 下面,为我工作。
      • 我还必须取消选中“在恢复之前进行尾部日志备份”才能恢复。
      • “在还原之前进行尾日志备份”这也需要取消选中。谢谢
      【解决方案6】:

      对我来说,解决方案是:

      1. 在左侧的 optoins 选项卡中勾选 Overwrite the existing database(WITH REPLACE)。

      2. 取消选中所有其他选项。

      3. 选择源和目标数据库。

      4. 点击确定。

      就是这样。

      【讨论】:

      • 也为我工作。我还必须取消选中“在还原之前进行尾日志备份”。
      【解决方案7】:
      Use Master
      alter database databasename set offline with rollback immediate;
      
      --Do Actual Restore
      RESTORE DATABASE databasename
      FROM DISK = 'path of bak file'
      WITH MOVE 'datafile_data' TO 'D:\newDATA\data.mdf',
      MOVE 'logfile_Log' TO 'D:\newDATA\DATA_log.ldf',replace
      
      alter database databasename set online with rollback immediate;
      GO
      

      【讨论】:

        【解决方案8】:

        这是我将数据库从生产恢复到开发的一种方式:

        注意:我通过 SSAS 工作每天将生产数据库推向开发:

        Step1:删除开发中的前一天备份:

        declare @sql varchar(1024);
        
        set @sql = 'DEL C:\ProdAEandAEXdataBACKUP\AE11.bak'
        exec master..xp_cmdshell @sql
        

        Step2:将生产数据库复制到开发:

        declare @cmdstring varchar(1000)
        set @cmdstring = 'copy \\Share\SQLDBBackup\AE11.bak C:\ProdAEandAEXdataBACKUP'
        exec master..xp_cmdshell @cmdstring 
        

        Step3:通过运行.sql脚本恢复

        SQLCMD -E -S dev-erpdata1 -b -i "C:\ProdAEandAEXdataBACKUP\AE11_Restore.sql"
        

        AE11_Restore.sql 文件中的代码:

        RESTORE DATABASE AE11
        FROM DISK = N'C:\ProdAEandAEXdataBACKUP\AE11.bak'
        WITH MOVE 'AE11' TO 'E:\SQL_DATA\AE11.mdf',
        MOVE 'AE11_log' TO 'D:\SQL_LOGS\AE11.ldf',
        RECOVERY;
        

        【讨论】:

          【解决方案9】:

          当没有足够的磁盘空间来恢复 Db 时,我收到此错误。清理一些空间就解决了。

          【讨论】:

            【解决方案10】:

            我刚刚重启了sqlexpress服务,然后恢复正常

            【讨论】:

            • 关于否决票我能说什么...对我来说它有效!
            • OP 的恢复脚本存在问题,因为他没有考虑到他的数据库可能已经在使用中。解决方案是使用适当的命令更新他的脚本,允许他独占访问数据库。虽然重新启动服务可能对您有用,但这不是解决他的问题的合适方法。
            • 对我来说(字面意思)上面的所有解决方案都不起作用,只有这个起作用。
            【解决方案11】:

            解决方案 1:重新启动 SQL 服务并尝试恢复 DB 解决方案2:重新启动系统/服务器并尝试恢复数据库 解决方案3:收回当前数据库,删除当前/目标数据库并尝试恢复数据库。

            【讨论】:

              【解决方案12】:

              将数据库设置为单用户模式对我来说不起作用,但将其脱机,然后将其重新联机确实有效。它位于 DB 的右键菜单中,位于 Tasks 下。

              请务必选中对话框中的“删除所有活动连接”选项。

              【讨论】:

                【解决方案13】:

                将原始数据库离线为我工作

                【讨论】:

                  【解决方案14】:

                  我在尝试在 MS SQL Server 2012 上恢复数据库时遇到了这个问题。

                  这对我有用

                  我必须首先对备份文件运行下面的RESTORE FILELISTONLY 命令以列出逻辑文件名:

                  RESTORE FILELISTONLY 
                      FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\my_db_backup.bak'
                  

                  这将分别显示数据库的数据和日志文件的 LogicalName 和相应的 PhysicalName

                  LogicalName      PhysicalName               
                  com.my_db        C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\com.my_db.mdf
                  com.my_db_log    C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\com.my_db_log.ldf
                  

                  我所要做的就是在我的数据库恢复脚本中分别替换数据库的数据和日志文件的 LogicalName 和相应的PhysicalName: p>

                  USE master;
                  GO
                  
                  ALTER DATABASE my_db SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
                  GO
                  
                      
                  RESTORE DATABASE my_db
                      FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\my_db_backup.bak'
                      WITH REPLACE,
                      MOVE 'com.my_db' TO 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\com.my_db.mdf',
                      MOVE 'com.my_db_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\com.my_db_log.ldf'
                  GO
                      
                  ALTER DATABASE my_db SET MULTI_USER;
                  GO
                  

                  并且数据库还原任务运行成功:

                  就是这样。

                  我希望这会有所帮助

                  【讨论】:

                    【解决方案15】:

                    当我不知道其他人在另一个 SSMS 会话中连接到数据库时,我收到了这个错误。在我将它们注销后,还原成功完成。

                    【讨论】:

                      猜你喜欢
                      • 2011-05-02
                      • 1970-01-01
                      • 2013-10-22
                      • 2020-05-03
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-08-05
                      • 1970-01-01
                      相关资源
                      最近更新 更多