當您嘗試卸離資料庫時,發生【Cannot detach the database '資料庫名稱' because it is currently in use.】錯誤,可能的解決方案

本文將介紹當您嘗試卸離資料庫時,發生【Cannot detach the database '資料庫名稱' because it is currently in use.】錯誤,可能的解決方案。

當您嘗試以下列 T-SQL 卸離資料庫時,發生【Cannot detach the database '資料庫名稱' because it is currently in use.】錯誤:

 

   1:  USE master
   2:  GO
   3:   
   4:  --1. 建立資料庫
   5:  IF (DB_ID(N'MyDB') IS NOT NULL)
   6:      DROP DATABASE MyDB
   7:  GO
   8:   
   9:  CREATE DATABASE [MyDB]
  10:   CONTAINMENT = NONE
  11:   ON  PRIMARY 
  12:  ( NAME = N'MyDB', FILENAME = N'D:\Temp\MyDB.mdf' , SIZE = 3072KB , FILEGROWTH = 1024KB )
  13:   LOG ON 
  14:  ( NAME = N'MyDB_log', FILENAME = N'D:\Temp\MyDB_log.ldf' , SIZE = 1024KB , FILEGROWTH = 10%)
  15:  GO
  16:  ALTER DATABASE [MyDB] SET COMPATIBILITY_LEVEL = 110
  17:  GO
  18:  ALTER DATABASE [MyDB] SET ANSI_NULL_DEFAULT OFF 
  19:  GO
  20:  ALTER DATABASE [MyDB] SET ANSI_NULLS OFF 
  21:  GO
  22:  ALTER DATABASE [MyDB] SET ANSI_PADDING OFF 
  23:  GO
  24:  ALTER DATABASE [MyDB] SET ANSI_WARNINGS OFF 
  25:  GO
  26:  ALTER DATABASE [MyDB] SET ARITHABORT OFF 
  27:  GO
  28:  ALTER DATABASE [MyDB] SET AUTO_CLOSE OFF 
  29:  GO
  30:  ALTER DATABASE [MyDB] SET AUTO_CREATE_STATISTICS ON 
  31:  GO
  32:  ALTER DATABASE [MyDB] SET AUTO_SHRINK OFF 
  33:  GO
  34:  ALTER DATABASE [MyDB] SET AUTO_UPDATE_STATISTICS ON 
  35:  GO
  36:  ALTER DATABASE [MyDB] SET CURSOR_CLOSE_ON_COMMIT OFF 
  37:  GO
  38:  ALTER DATABASE [MyDB] SET CURSOR_DEFAULT  GLOBAL 
  39:  GO
  40:  ALTER DATABASE [MyDB] SET CONCAT_NULL_YIELDS_NULL OFF 
  41:  GO
  42:  ALTER DATABASE [MyDB] SET NUMERIC_ROUNDABORT OFF 
  43:  GO
  44:  ALTER DATABASE [MyDB] SET QUOTED_IDENTIFIER OFF 
  45:  GO
  46:  ALTER DATABASE [MyDB] SET RECURSIVE_TRIGGERS OFF 
  47:  GO
  48:  ALTER DATABASE [MyDB] SET  DISABLE_BROKER 
  49:  GO
  50:  ALTER DATABASE [MyDB] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 
  51:  GO
  52:  ALTER DATABASE [MyDB] SET DATE_CORRELATION_OPTIMIZATION OFF 
  53:  GO
  54:  ALTER DATABASE [MyDB] SET PARAMETERIZATION SIMPLE 
  55:  GO
  56:  ALTER DATABASE [MyDB] SET READ_COMMITTED_SNAPSHOT OFF 
  57:  GO
  58:  ALTER DATABASE [MyDB] SET  READ_WRITE 
  59:  GO
  60:  ALTER DATABASE [MyDB] SET RECOVERY SIMPLE 
  61:  GO
  62:  ALTER DATABASE [MyDB] SET  MULTI_USER 
  63:  GO
  64:  ALTER DATABASE [MyDB] SET PAGE_VERIFY CHECKSUM  
  65:  GO
  66:  ALTER DATABASE [MyDB] SET TARGET_RECOVERY_TIME = 0 SECONDS 
  67:  GO
  68:  USE [MyDB]
  69:  GO
  70:  IF NOT EXISTS (SELECT name FROM sys.filegroups WHERE is_default=1 AND name = N'PRIMARY') ALTER DATABASE [MyDB] MODIFY FILEGROUP [PRIMARY] DEFAULT
  71:  GO
  72:   
  73:  --2.建立測試資料表及測試資料
  74:  CREATE TABLE t1 (c1 int)
  75:   
  76:  INSERT INTO t1 
  77:  SELECT 1 UNION ALL
  78:  SELECT 2 UNION ALL
  79:  SELECT 3 UNION ALL
  80:  SELECT 4 UNION ALL
  81:  SELECT 5
  82:   
  83:  GO 
  84:   
  85:  --3.查詢資料
  86:  USE MyDB
  87:  go
  88:   
  89:  SELECT *
  90:  FROM t1
  91:  GO
  92:   
  93:  --4.設定資料庫為SINGLE_USER模式
  94:  ALTER DATABASE [MyDB] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE
  95:  GO
  96:  --5.卸載資料庫
  97:  EXEC master.dbo.sp_detach_db @dbname = N'MyDB'
  98:  GO

 

【執行結果】

image

 

或是您透過自行開發的 AP 嘗試卸離資料庫時,發生下列的錯誤訊息:

 

   1:  using (SqlConnection con = new SqlConnection(@"Data Source=(localdb)\v11.0;Initial Catalog=MyDB;Integrated Security=True;"))
   2:  {
   3:      using (SqlDataAdapter adapter = new SqlDataAdapter("select * from t1", con))
   4:      {
   5:          DataSet ds = new DataSet();
   6:          adapter.Fill(ds, "t1");
   7:          foreach (DataRow dr in ds.Tables[0].Rows)
   8:          {
   9:              Console.WriteLine(String.Format("{0}", dr[0]));
  10:          }
  11:      }
  12:     
  13:      if (con.State != ConnectionState.Open) con.Open();
  14:      string strCmd = @"ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; 
  15:                                EXEC master.dbo.sp_detach_db @dbname = N'MyDB'" ;
  16:      using (SqlCommand cmd = new SqlCommand(strCmd, con))
  17:      {
  18:          cmd.ExecuteNonQuery();
  19:      }
  20:  }
  21:  Console.ReadKey();

 

【執行結果】

image

 

不管您使用哪種方法,問題都出在於您沒辦法卸離仍有連線連接到您要卸離的資料庫,您可以在發生上述情況時,利用 sp_who 或 sp_who2 來查看連線狀況(如下圖):

 

image

image

 

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

 

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

 

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

 

   1:  using (SqlConnection con = new SqlConnection(@"Data Source=(localdb)\v11.0;Initial Catalog=MyDB;Integrated Security=True;"))
   2:  {
   3:      using (SqlDataAdapter adapter = new SqlDataAdapter("select * from t1", con))
   4:      {
   5:          DataSet ds = new DataSet();
   6:          adapter.Fill(ds, "t1");
   7:          foreach (DataRow dr in ds.Tables[0].Rows)
   8:          {
   9:              Console.WriteLine(String.Format("{0}", dr[0]));
  10:          }
  11:      }
  12:     
  13:      if (con.State != ConnectionState.Open) con.Open();
  14:      string strCmd = @"ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; 
  15:                        USE master; 
  16:                        EXEC master.dbo.sp_detach_db @dbname = N'MyDB'" ;
  17:      using (SqlCommand cmd = new SqlCommand(strCmd, con))
  18:      {
  19:          cmd.ExecuteNonQuery();
  20:      }
  21:  }
  22:  Console.ReadKey();

 

【參考資料】