在 ASP.NET 應用程式中整合資料庫備份/還原功能,可讓管理員透過網頁介面操作,無需直接登入 SSMS。核心原理:執行 T-SQL BACKUP DATABASE / RESTORE DATABASE 指令,需注意連線字串、檔案路徑權限、單一使用者模式等細節。
dbcreator / sysadmin 權限的登入(如 sa 或專用管理帳號)。public string BackupDatabase(string dbName, string backupFolder, string fileName)
{
// 1. 驗證參數
if (string.IsNullOrWhiteSpace(dbName)) throw new ArgumentException("資料庫名稱不可空白");
if (string.IsNullOrWhiteSpace(backupFolder)) throw new ArgumentException("備份資料夾不可空白");
// 2. 確保資料夾存在
if (!Directory.Exists(backupFolder))
Directory.CreateDirectory(backupFolder);
string fullPath = Path.Combine(backupFolder, $"{fileName}.bak");
// 3. 檢查檔案是否存在(避免覆蓋)
if (File.Exists(fullPath))
throw new InvalidOperationException($"備份檔案已存在:{fullPath}");
// 4. 連線字串:連到 master 執行 BACKUP
string connStr = $"Server=.;Database=master;User ID=sa;Password=YourStrongPwd;Connection Timeout=30;";
// 5. BACKUP 指令:WITH INIT, COMPRESSION, STATS
string sql = $@"
BACKUP DATABASE [{dbName}]
TO DISK = N'{fullPath.Replace("'", "''")}'
WITH
INIT, -- 覆寫現有備份集
COMPRESSION, -- 壓縮 (SQL 2008+)
STATS = 10, -- 進度百分比
CHECKSUM; -- 驗證頁面檢查碼
";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
conn.Open();
cmd.CommandTimeout = 3600; // 大資料庫可能需 1 小時以上
cmd.ExecuteNonQuery();
}
return fullPath;
}
public void RestoreDatabase(string dbName, string bakFilePath, bool overwrite = true)
{
if (!File.Exists(bakFilePath))
throw new FileNotFoundException("備份檔案不存在", bakFilePath);
string connStr = "Server=.;Database=master;User ID=sa;Password=YourStrongPwd;Connection Timeout=30;";
// 關鍵:先設為 SINGLE_USER 與 ROLLBACK IMMEDIATE 踢掉其他連線
string sql = $@"
ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE [{dbName}]
FROM DISK = N'{bakFilePath.Replace("'", "''")}'
WITH
REPLACE, -- 覆寫現有資料庫
STATS = 10,
CHECKSUM;
ALTER DATABASE [{dbName}] SET MULTI_USER;
";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
conn.Open();
cmd.CommandTimeout = 3600;
cmd.ExecuteNonQuery();
}
}
<asp:DropDownList ID="ddlDatabases" runat="server" />
<asp:TextBox ID="txtBackupName" runat="server" Placeholder="輸入備份檔名" />
<asp:Button ID="btnBackup" Text="備份" OnClick="btnBackup_Click" runat="server" />
<br />
<asp:FileUpload ID="fuRestore" runat="server" />
<asp:Button ID="btnRestore" Text="還原" OnClick="btnRestore_Click" runat="server" />
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) LoadDatabases();
}
void LoadDatabases()
{
using (var conn = new SqlConnection("Server=.;Database=master;User ID=sa;Password=xxx;"))
using (var cmd = new SqlCommand("SELECT name FROM sys.databases WHERE database_id > 4 ORDER BY name", conn))
{
conn.Open();
ddlDatabases.DataSource = cmd.ExecuteReader();
ddlDatabases.DataTextField = "name";
ddlDatabases.DataValueField = "name";
ddlDatabases.DataBind();
}
}
protected void btnBackup_Click(object sender, EventArgs e)
{
try
{
string path = BackupDatabase(ddlDatabases.SelectedValue, @"D:\SQLBackups\", txtBackupName.Text.Trim());
ShowAlert($"備份成功:{path}");
}
catch (Exception ex) { ShowAlert("備份失敗:" + ex.Message); }
}
protected void btnRestore_Click(object sender, EventArgs e)
{
if (!fuRestore.HasFile) { ShowAlert("請選擇 .bak 檔案"); return; }
if (!fuRestore.FileName.EndsWith(".bak", StringComparison.OrdinalIgnoreCase))
{ ShowAlert("僅支援 .bak 檔案"); return; }
string tempPath = Path.Combine(Server.MapPath("~/App_Data/Temp"), fuRestore.FileName);
fuRestore.SaveAs(tempPath);
try
{
RestoreDatabase(ddlDatabases.SelectedValue, tempPath);
ShowAlert("還原成功");
}
catch (Exception ex) { ShowAlert("還原失敗:" + ex.Message); }
finally { if (File.Exists(tempPath)) File.Delete(tempPath); }
}
void ShowAlert(string msg) => ClientScript.RegisterStartupScript(GetType(), "alert", $"alert('{msg.Replace("'", "\\'")}');", true);
| 項目 | 說明 |
|---|---|
| 權限 | SQL Server 服務帳號需對 .bak 檔案路徑有讀寫權;網站對備份資料夾需寫入權 |
| 單一使用者模式 | 還原前 SET SINGLE_USER WITH ROLLBACK IMMEDIATE 強制斷開其他連線,否則 RESTORE 會失敗 |
| 檔案路徑 | BACKUP/RESTORE 路徑是 **SQL Server 服務端視角**,非網站伺服器視角;若跨機器需用 UNC 路徑 \\Server\Share\file.bak |
| 大資料庫 | 設定 CommandTimeout、考慮分割備份、非同步執行避免網頁逾時 |
| 安全性 | 嚴格驗證輸入、防止 SQL Injection(參數化無法用於 BACKUP 指令,需手動 Escape 單引號)、限制管理員角色存取 |
大型資料庫備份/還原耗時長,建議:
SqlCommand.ExecuteNonQueryAsync 配合 CancellationToken。STATS 進度事件(需 CLR 整合或自訂擴充事件)。此功能屬高風險操作,**務必加上詳細稽核日誌、操作確認對話框、權限管控**。