關於作者:

本文由微軟最有價值專家 MVP TerryChuang 提供。微軟十分感謝 MVP 主動地將他們的經驗與上百萬名其他技術使用者交流。MVP TerryChuang 同時也將此篇文章放在他的部落格內,歡迎您按 此處  瀏覽 MVP TerryChuang 更多的技術文章、經驗分享與觀點。

問題的來龍去脈

當您嘗試於 SSMS 或利用程式方式卸離資料庫時,可能發生【無法卸離 資料庫 '資料庫名稱',因為目前正在使用中】的錯誤。

  • 下列程式碼用來重現於 SSMS 中使用 T-SQL 嘗試卸離資料庫,可能發生錯誤的狀況:

USE master GO --1. 建立資料庫 IF (DB_ID(N'MyDB') IS NOT NULL) DROP DATABASE MyDB GO CREATE DATABASE [MyDB] CONTAINMENT = NONE ON PRIMARY ( NAME = N'MyDB', FILENAME = N'D:\MyDB.mdf' , SIZE = 3072KB , FILEGROWTH = 1024KB ) LOG ON ( NAME = N'MyDB_log', FILENAME = N'D:\MyDB_log.ldf' , SIZE = 1024KB , FILEGROWTH = 10%) GO USE [MyDB] GO IF NOT EXISTS (SELECT name FROM sys.filegroups WHERE is_default=1 AND name = N'PRIMARY') ALTER DATABASE [MyDB] MODIFY FILEGROUP [PRIMARY] DEFAULT GO --2.建立測試資料表及測試資料 CREATE TABLE t1 (c1 int) INSERT INTO t1 SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 GO --3.查詢資料 USE MyDB go SELECT * FROM t1 GO --4.設定資料庫為SINGLE_USER模式 ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO --5.卸載資料庫 EXEC master.dbo.sp_detach_db @dbname = N'MyDB'

執行結果:
 


  • 或是您透過自行開發的 AP 嘗試卸離資料庫時,發生上述的錯誤訊息。以下程式碼用來重現這個錯誤:

using (SqlConnection con = new SqlConnection(@"Data Source=.;Initial Catalog=MyDB;UIntegrated Security=True;")) { using (SqlDataAdapter adapter = new SqlDataAdapter("select * from t1", con)) { DataSet ds = new DataSet(); adapter.Fill(ds, "t1"); foreach (DataRow dr in ds.Tables[0].Rows) { Console.WriteLine(String.Format("{0}", dr[0])); } } if (con.State != ConnectionState.Open) con.Open(); string strCmd = @"ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; EXEC master.dbo.sp_detach_db @dbname = N'MyDB'"; using (SqlCommand cmd = new SqlCommand(strCmd, con)) { cmd.ExecuteNonQuery(); } } Console.ReadKey();

執行結果:





問題的發生原因

不管您使用哪種方法,問題都出在於您沒辦法卸離仍有連線連接到您要卸離的資料庫,換言之,您必須先中斷所有連線之後才可以順利卸除。您可以在發生上述錯誤時,利用 sp_who 或 sp_who2 來查看連線狀況(如下圖):





問題的解決方法

只要您把上圖中使用到您要卸離資料庫的 SPID 利用 kill  敘述刪除之後,就可以順利卸離資料庫。或是您也可以在卸離資料庫前,先切換到其他資料庫(像是master)之後再進行卸離,就可以順利完成了,如下列T-SQL 的4.1。

--4.設定資料庫為SINGLE_USER模式
ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
--4.1 先將資料庫切換到非要卸離的資料庫
USE master
GO
--5.卸載資料庫
EXEC master.dbo.sp_detach_db @dbname = N'

在 AP 中也是一樣的做法,如下列程式碼的第 15 列:

using (SqlConnection con = new SqlConnection(@"Data Source=(localdb)\v11.0;Initial Catalog=MyDB;
Integrated Security=True;"))
{
using (SqlDataAdapter adapter = new SqlDataAdapter("select * from t1", con))
{
DataSet ds = new DataSet();
adapter.Fill(ds, "t1");
foreach (DataRow dr in ds.Tables[0].Rows)
{
Console.WriteLine(String.Format("{0}", dr[0]));
}
}

if (con.State != ConnectionState.Open) con.Open();
string strCmd = @"ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
USE master;
EXEC master.dbo.sp_detach_db @dbname = N'MyDB'" ;
using (SqlCommand cmd = new SqlCommand(strCmd, con))
{
cmd.ExecuteNonQuery();
}
}
Console.ReadKey();



其他相關資訊

請讓我們知道

還滿意我們寫的內容嗎?無論您是遇到了以下任何一種情況:
「太好了!問題解決了。」
「問題沒有解決,我有更好的建議。」
都歡迎您利用本篇文章底部的意見調查表,寫下您寶貴的意見。也期待您的鼓勵,讓我們為您創造更多實用的技術文章。

Need more help?

Expand your skills
Explore Training
Get new features first
Join Microsoft Insiders

Was this information helpful?

How satisfied are you with the translation quality?
What affected your experience?

Thank you for your feedback!

×