最近在做一個資料擷取模組,遇到這樣一個情境,就是需要將Database Backup檔案還原到指定資料庫執行個體下再採集資料。本機測試都沒有問題,可一拿到真實環境中測試卻發現了一個很大的Bug。所有的資料庫都還原不上,很糾結。因為我本以為SQL SERVER 會還原到預設路徑下,其實不然。
當我拿到真實Database Backup檔案時,我首先在資料庫中運行 restore database RestoreDbName from disk ='H:\DBFolder\Db_Back' ,執行結果如下:
到現在我依然不知道是怎麼回事,因為我自己建立的資料庫再還原是好使的。怎麼會這樣?一個意外讓我發現原來我建的資料庫是在資料庫執行個體預設的路徑下,而真實Database Backup檔案則不是,它的路徑是客戶機器上的,肯定不一樣。為了驗證這個發現,我做了如下的工作。
第一步:建立資料庫,create database TestDb 。
第二步:備份資料庫。
第三步:直接還原資料庫,restore database RestoreDbName from disk ='I:\TestDatabase' ,執行成功。
第四步:還原資料庫,這時候我不是採用預設還原,而是將資料庫還原到系統的另一個路徑下,代碼如下:
restore database RestoreDbName from disk ='I:\TestDatabase' with replace, move 'TestDb' to 'H:\DBFolder\RestoreDbName_Data.mdf', move 'TestDb_log' to 'H:\DBFolder\RestoreDbName_Log.ldf'
執行結果:
第五步:再次備份資料庫RestoreDbName。備份後我們用 filelistonly 可以看到當前Database Backup檔案的備份路徑( restore filelistonly from disk = 'I:\RestoreDb' ), 執行後結果如下:
從這裡我們可以看到當前Database Backup檔案的真實實體路徑。
第六步:當我再次執行 restore database RestoreDbName from disk ='I:\RestoreDb' ,執行錯誤。出現了和真實環境一樣的錯誤。原來如上文所述那樣,Database Backup檔案在還原時,如果當前資料庫執行個體的預設路徑和Database Backup檔案不相符時需要通過move來解決,而不能單純的 Restore。
於是我又重新寫了一下Database Backup檔案還原的相關方法,如下所示。通過這個方法就能簡單的實現Database Backup檔案還原了。
View Code
/// <summary>
/// 還原資料庫檔案
/// </summary>
/// <param name="basePath">電子賬簿所在根目錄</param>
/// <param name="fileName">Database Backup檔案名稱</param>
/// <param name="databaseName">需要還原的資料庫名稱</param>
/// <param name="conn">資料庫連接</param>
private bool RestoreDataBase(string basePath, string fileName, string databaseName, SqlConnection conn)
{
SqlCommand command = null;
try
{
string restoreStr = string.Empty;
string getLogicFileName = string.Format("restore filelistonly from disk ='{0}'", Path.Combine(basePath, fileName));
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(getLogicFileName, conn);
da.Fill(ds);
if (ds.Tables == null || ds.Tables[0].Rows.Count == 0) return false;
foreach (DataRow dr in ds.Tables[0].Rows)
{
//尋找資料庫邏輯檔案名稱
if ("D".Equals(dr["Type"].ToString()))
restoreStr += string.Format("move '{0}' to '{1}',", dr["LogicalName"].ToString(), Path.Combine(basePath, databaseName) + "_Data.mdf");
//尋找資料庫記錄檔名稱
else if ("L".Equals(dr["Type"].ToString()))
restoreStr += string.Format("move '{0}' to '{1}',", dr["LogicalName"].ToString(), Path.Combine(basePath, databaseName) + "_Log.ldf");
}
if (string.IsNullOrEmpty(restoreStr))
restoreStr = string.Format("restore database {0} from disk ='{1}'", databaseName, Path.Combine(basePath, fileName));
else
{
restoreStr = string.Format("restore database {0} from disk ='{1}' with replace,", databaseName, Path.Combine(basePath, fileName)) + restoreStr.TrimEnd(',');
}
command = new SqlCommand(restoreStr, conn);
conn.Open();
command.ExecuteNonQuery();
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
conn.Close();
}
}