2010-10-28 33 views
33

Tôi đang sử dụng đoạn mã sau để khôi phục lại cơ sở dữ liệu,truy cập độc quyền không thể thu được vì cơ sở dữ liệu được sử dụng

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(); 
    } 
} 

nhưng tôi nhận được dưới đây ngoại lệ

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

Làm thế nào tôi có thể sửa chữa nó?

Trả lời

48

Một khôi phục chỉ có thể xảy ra nếu cơ sở dữ liệu không có bất kỳ kết nối đến nó (ngoài bạn). Cách dễ dàng trên máy chủ MS SQL để khởi động tất cả người dùng là:

ALTER DATABASE [MyDB] SET Single_User WITH Rollback Immediate 
GO 

Bây giờ, bạn có thể thực hiện khôi phục không bị ảnh hưởng. Hãy chắc chắn rằng bạn đặt nó trở lại chế độ đa người dùng khi bạn đang thực hiện với sự khôi phục:

ALTER DATABASE [MyDB] SET Multi_User 
GO 
+0

Cơ sở dữ liệu của tôi nằm trong 'D: \ SQL \ RRDB.mdf', tôi phải thay thế' MyDB' bằng đường dẫn đầy đủ hoặc chỉ 'RRDB.mdf'? –

+0

Bạn chỉ cần RRDB. – KeithS

+0

Trong câu trả lời tiếp theo, tôi đã sử dụng Full Path và nó đã hoạt động. –

1

Lý do cho vấn đề này là hiển nhiên (kết nối đến cơ sở dữ liệu hiện đang mở/hoạt động), nhưng sử dụng sau đây (google nó quá vì vậy bạn có hiểu nó) và nó sẽ ổn thôi:

Alter Database YOURDB 
SET SINGLE_USER With ROLLBACK IMMEDIATE 
GO 

Rõ ràng, hãy thay thế YOURDDB bằng tên cơ sở dữ liệu của bạn và chạy với DB chính.

Oh, và chỉ trong trường hợp, nếu bạn nhận được nó 'mắc kẹt' trong chế độ người dùng đơn lẻ, điều này sẽ undo đó:

Alter Database YOURDB 
SET MULTI_USER With ROLLBACK IMMEDIATE 
GO 

Hope this helps.

EDIT:

Bạn cũng có có thể làm theo this, để nhìn thấy nơi các kết nối từ, và các thông tin khác:

Tôi đã thử nghiệm trong khi điều này có dịch vụ chạy mà sẽ kết nối lại với cơ sở dữ liệu . Tôi thấy bạn phải đặt thành Chế độ người dùng đơn, sau đó chạy sp_who2 đến xem kết nối một là đến từ đâu và lưu ý SPID. Bạn có thể chạy lệnh giết cho SPID và khôi phục trong cùng một giao dịch và nó sẽ được thực hiện. Dưới đây là trình tự tôi đã sử dụng:

SỬ DỤNG TỔNG ALTER DATABASE DatabaseName SET SINGLE_USER VỚI ROLLBACK NGAY GO

-Đây sẽ làm cho nó nên chỉ có một kết nối đến cơ sở dữ liệu có thể được thực hiện. -Run lệnh sau để xem nơi mọi kết nối định kỳ tới cơ sở dữ liệu sẽ đến từ đó.

EXEC SP_WHO2

-Kiểm tra danh sách này, tìm trong cột DBName. Nếu cơ sở dữ liệu được liệt kê , hãy kiểm tra cột Tên chương trình và Tên máy chủ để xem ai là tìm cách kết nối. -Nếu đây không phải là dịch vụ hoặc ứng dụng khác sẽ tự động kết nối lại có thể tắt, hãy lưu ý số trong cột SPID để hủy kết nối và ngay lập tức bắt đầu bản sao lưu. Thay thế SPID bên dưới chỉ với số .

KILL SPID RESTORE DATABASE DATABASENAME TỪ DISK = 'X: \ PATHTO \ BACKUP.BAK 'GO

-Nếu điều này hoàn tất thành công, chúng tôi có thể đặt cơ sở dữ liệu mới được khôi phục trở lại chế độ đa người dùng.

ALTER DATABASE DatabaseName SET MULTI_USER VỚI ROLLBACK NGAY GO

+0

-1 cho đạo văn. Văn bản bên dưới EDIT được sao chép trực tiếp từ câu trả lời của TheOneBlackMage [ở đây] (http://social.msdn.microsoft.com/Forums/en-US/sqldisasterrecovery/thread/aad41cbb-10cb-4109-9e55-aab048bbeb9d). –

+0

"Gọi cảnh sát internet, tôi đã nhầm lẫn và bây giờ tôi đang trích dẫn các trang web để thử và mua lại bản thân mình" <- Joe Stefanelli, 28/10/2010 EDIT: Anh ấy đã xóa nhận xét của mình và để tôi bỏ phiếu. LOL – Dave

+0

1. Nhìn vào lịch sử chỉnh sửa, bạn đã thêm siêu liên kết * sau * Tôi đã đăng nhận xét của mình. 2. Bất kỳ ý tưởng nào tại sao tôi nhận được 4 downvotes trên một số câu trả lời khác của tôi ngay lập tức sau khi tôi đăng bình luận của tôi? –

14

Vì vậy, tôi đã viết các phương pháp dưới đây để khôi phục lại cơ sở dữ liệu của tôi,
Tôi ở đúng cách?

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"; 
    } 
} 
+0

có vẻ tốt với tôi, trong hiệu trưởng. Tôi không thể chạy nó, nhưng không có lỗi rõ ràng. Hãy nhớ rằng 'người dùng đơn được đặt với rollback ngay lập tức' sẽ đóng tất cả các kết nối (ngoại trừ một lệnh đang chạy lệnh) và khôi phục tất cả các giao dịch mặc dù. – Dave

8

Cách tiếp cận tốt nhất

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 
  • VỚI ROLLBACK NGAY - tùy chọn này không đợi cho các giao dịch để hoàn thành nó chỉ bắt đầu lăn trở lại giao dịch tất cả các mở
  • VỚI ROLLBACK SAU nnn - tùy chọn này wi ll rollback tất cả các giao dịch mở sau khi đợi nnn giây cho các giao dịch mở đến hoàn tất. Trong ví dụ của chúng tôi, chúng tôi xác định rằng quá trình cần chờ 30 giây trước khi quay lại bất kỳ giao dịch đang mở nào.

  • Khi RESTRICTED_USER được chỉ định, chỉ các thành viên của db_owner, dbcreator, hoặc sysadmin vai trò có thể sử dụng cơ sở dữ liệu. MULTI_USER trả lại cơ sở dữ liệu về trạng thái hoạt động bình thường của nó.


Cách 2: sử dụng SSMS 2008 R2 chúng ta có thể làm điều tương tự

  1. nhấp chuột phải sở hữu cơ sở dữ liệu
  2. đi đến lựa chọn -> phần cuối với tiêu đề của bang
  3. thay đổi Giới hạn quyền truy cập đến SINGLE_USER
  4. câu trả lời đúng cho câu hỏi hữu ích này mà chỉ ra rằng loại hành động này sẽ đóng mọi kết nối khác và tôi đoán nó là điều duy nhất chúng tôi đang tìm kiếm ở đây để bởi vượt qua lỗi

Để thay đổi thuộc tính cơ sở dữ liệu, SQL Server phải đóng tất cả các kết nối khác vào cơ sở dữ liệu. Bạn có chắc chắn muốn thay đổi thuộc tính và đóng tất cả các kết nối khác không? có hoặc không

  1. khôi phục cơ sở dữ liệu của bạn
  2. làm bước 1-4 đổi Hạn chế tiếp cận trở lại MULTI_USER

cách thứ 3: các lệnh sau đây cũng sẽ chặt chẽ tất cả các kết nối.

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

tại cơ sở dữ liệu đã sẵn sàng cho khôi phục

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

+1

SET OFFLINE & SET ONLINE cũng hoạt động trên SQL 2008. Lưu ý rằng cả hai phải được thực hiện liên tiếp; nếu DB ngoại tuyến thì không thể khôi phục. –

+0

nếu DB đang ngoại tuyến, nó có thể được khôi phục. Tôi thử nghiệm nó trên cập nhật 2008 R2 và nó đã làm việc. thường các phương pháp được đề cập không hoạt động và bạn phải sử dụng màn hình hoạt động để giết các phiên hoạt động. –

6

Bạn có thể sử dụng phương pháp trên SMO đối tượng SQLServer để kiil tất cả các quy trình trên một cơ sở dữ liệu theo quy định trước khi thực hiện một khôi phục:

sqlServer.KillAllProcesses("databaseName"); 
1
  • chỉ có thể kết nối với cơ sở dữ liệu. -Run Lệnh sau đây để xem nơi mà bất kỳ kết nối định kỳ đến cơ sở dữ liệu đến từ đâu.

    EXEC SP_WHO2 
    
  • Kiểm tra danh sách này, tìm trong cột DBName. Nếu cơ sở dữ liệu được liệt kê, hãy kiểm tra cột ProgramName và Tên máy chủ để xem ai đang cố gắng kết nối.

  • Nếu đó không phải là dịch vụ hoặc ứng dụng khác tự động kết nối lại có thể tắt, hãy lưu ý số trong cột SPID để hủy kết nối và bắt đầu sao lưu ngay lập tức. Thay thế SPID bên dưới chỉ bằng số.

    KILL SPID RESTORE DATABASE DATABASENAME FROM DISK = 'X:\PATHTO\BACKUP.BAK' GO 
    
  • Nếu điều này hoàn tất thành công, chúng tôi có thể đặt cơ sở dữ liệu mới được khôi phục về chế độ đa người dùng.

    ALTER DATABASE DATABASENAME SET MULTI_USER WITH ROLLBACK IMMEDIATE GO 
    
Các vấn đề liên quan