Эксклюзивный доступ не может быть получен, поскольку база данных используется

Я использую следующий код для восстановления баз данных,

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'."

Как я могу это исправить?


person Mohammad Dayyan    schedule 28.10.2010    source источник


Ответы (6)


Восстановление может произойти только в том случае, если база данных не имеет к ней никаких подключений (кроме ваших). Простой способ на MS SQL Server отключить всех пользователей:

ALTER DATABASE [MyDB] SET Single_User WITH Rollback Immediate
GO

Теперь вы можете выполнять восстановление безнаказанно. Убедитесь, что вы вернули его в многопользовательский режим, когда закончите восстановление:

ALTER DATABASE [MyDB] SET Multi_User
GO
person KeithS    schedule 28.10.2010
comment
Моя база данных находится в D:\SQL\RRDB.mdf, мне нужно заменить MyDB полным путем или только RRDB.mdf? - person Mohammad Dayyan; 29.10.2010
comment
Я сделал базу данных Single_user, но столкнулся с той же проблемой! - person Ahmed Ahmed; 26.11.2013
comment
Вы должны поставить With Rollback Immediate в конце оператора; который немедленно откатывает все ожидающие транзакции при разрыве соединений. Просто установив его на одного пользователя, по умолчанию соединения будут оставаться открытыми до завершения транзакций. - person KeithS; 16.12.2013
comment
Не работает для меня. Я получаю ту же ошибку Не удалось получить монопольный доступ... - person AH.; 07.09.2015

Таким образом, я написал приведенный ниже метод для восстановления моей базы данных.
Правильно ли я понимаю?

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";
    }
}
person Mohammad Dayyan    schedule 29.10.2010
comment
выглядит хорошо для меня, в принципе. У меня не получается запустить, но явных ошибок нет. Имейте в виду, что «установить одного пользователя с немедленным откатом» закроет все соединения (кроме того, который выполняет команду) и отменит все транзакции. - person Dave; 29.10.2010

Лучший подход

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 
  • С НЕМЕДЛЕННЫМ ОТКАТОМ: эта опция не ждет завершения транзакций, а просто начинает откат всех открытых транзакций.
  • WITH ROLLBACK AFTER nnn — этот параметр откатывает все открытые транзакции после ожидания nnn секунд для завершения открытых транзакций. В нашем примере мы указываем, что процесс должен ждать 30 секунд перед откатом любых открытых транзакций.

  • Если указано RESTRICTED_USER, только члены ролей db_owner, dbcreator или sysadmin могут использовать базу данных. MULTI_USER возвращает базу данных в нормальное рабочее состояние.


2-й способ: с помощью ssms 2008 R2 мы можем сделать то же самое

  1. щелкните правой кнопкой мыши свойство базы данных
  2. перейдите к параметрам -> последний раздел с заголовком state
  3. измените Ограничить доступ на SINGLE_USER
  4. ответьте «да» на этот полезный вопрос, который показывает, что такого рода действия закроют все другие соединения, и я думаю, что это единственное, что мы ищем здесь, чтобы обойти ошибку

Чтобы изменить свойства базы данных, SQL Server должен закрыть все другие соединения с базой данных. Вы уверены, что хотите изменить свойства и закрыть все остальные подключения? да или нет

  1. восстановить вашу базу данных
  2. выполните шаги 1–4, изменив Ограничение доступа обратно на MULTI_USER.

3-й способ: следующие команды также закроют все соединения.

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

теперь база данных готова к восстановлению

Подробнее (mssqltips: Получение эксклюзивного доступа к восстановить базы данных SQL Server)

person Iman    schedule 19.02.2012
comment
SET OFFLINE и SET ONLINE также работали на SQL 2008. Обратите внимание, что оба действия должны выполняться последовательно; если БД отключена, ее нельзя восстановить. - person Mark Maslar; 15.07.2012
comment
если БД отключена, ее можно восстановить. Я тестировал это на обновленной версии 2008 R2, и это сработало. обычно упомянутые методы не работают, и вы должны использовать монитор активности, чтобы убить активные сеансы. - person Iman; 14.05.2013

Вы можете использовать метод для объекта SMO SqlServer, чтобы убить все процессы в указанной базе данных перед выполнением восстановления:

sqlServer.KillAllProcesses("databaseName");
person Martin Bell    schedule 21.07.2013

Причина этой проблемы очевидна (подключения к базе данных в настоящее время открыты/активны), но используйте следующее (погуглите, чтобы вы это поняли), и все будет в порядке:

Alter Database YOURDB   
SET SINGLE_USER With ROLLBACK IMMEDIATE
GO

Очевидно, замените YOURDDB на имя вашей базы данных и запустите его для главной БД.

О, и на всякий случай, если вы «застряли» в однопользовательском режиме, это отменит его:

Alter Database YOURDB   
SET MULTI_USER With ROLLBACK IMMEDIATE
GO

Надеюсь это поможет.

РЕДАКТИРОВАТЬ:

Вы также можете подписаться на эту, чтобы увидеть, откуда идут соединения, и другую информацию:

Я тестировал это, когда работали службы, которые повторно подключались к базе данных. Я обнаружил, что вам нужно установить однопользовательский режим, а затем запустить sp_who2, чтобы увидеть, откуда исходит одно соединение, и отметить SPID. Вы можете запустить команду kill для этого SPID и восстановить в одной и той же транзакции, и она должна пройти. Вот последовательность, которую я использовал:

USE MASTER ALTER DATABASE NAME DATABASENAME SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO

-Это позволит сделать только одно подключение к базе данных. -Выполните следующую команду, чтобы увидеть, откуда поступают какие-либо повторяющиеся подключения к базе данных.

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

person Dave    schedule 28.10.2010
comment
-1 за плагиат. Текст под EDIT скопирован непосредственно из ответа TheOneBlackMage здесь. - person Joe Stefanelli; 29.10.2010
comment
Позвоните в интернет-полицию, я совершил ошибку, и теперь я цитирую веб-сайты, чтобы попытаться искупить свою вину ‹- Джо Стефанелли, 28/10/2010 РЕДАКТИРОВАТЬ: Он удалил свой комментарий и оставил меня заминусованным. ржу не могу - person Dave; 29.10.2010
comment
1. Глядя на историю редактирования, вы добавили гиперссылку после того, как я разместил свой комментарий. 2. Есть идеи, почему я получил 4 отрицательных голоса за некоторые из моих других ответов сразу после того, как опубликовал свой комментарий? - person Joe Stefanelli; 29.10.2010
comment
Плагиат (из ВИКИПЕДИИ): неправомерное присвоение, близкое подражание или хищение и публикация языка, мыслей, идей или выражений другого автора и представление их как собственной оригинальной работы. ‹- похоже ли внутри этой гигантской цитаты, что я хочу выдать эту ЦИТАТУ за свою собственную? Повзрослейте и сделайте что-нибудь продуктивное, например, узнайте, что означает плагиат, прежде чем вы начнете бросать обвинения. - person Dave; 01.11.2010

  • можно сделать только одно подключение к базе данных. -Выполните следующую команду, чтобы увидеть, откуда поступают какие-либо повторяющиеся подключения к базе данных.

    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
    
person karthik    schedule 10.09.2013