首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 備份與還原 SQL Server 資料庫完整實作

     編輯:關於ASP.NET

在 ASP.NET 應用程式中整合資料庫備份/還原功能,可讓管理員透過網頁介面操作,無需直接登入 SSMS。核心原理:執行 T-SQL BACKUP DATABASE / RESTORE DATABASE 指令,需注意連線字串、檔案路徑權限、單一使用者模式等細節。

前置需求

  • SQL Server 服務帳號對備份資料夾具備 **讀寫權限**。
  • ASP.NET 應用程式集區身分識別(或模擬帳號)對備份資料夾具備 **寫入權限**(備份時);還原時需 SQL Server 服務帳號可讀取 .bak 檔。
  • 連線字串使用具備 dbcreator / sysadmin 權限的登入(如 sa 或專用管理帳號)。

1. 備份資料庫

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

2. 還原資料庫


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

3. ASP.NET 頁面整合範例

<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 單引號)、限制管理員角色存取

進階:非同步執行與進度回報

大型資料庫備份/還原耗時長,建議:

  1. 使用 SqlCommand.ExecuteNonQueryAsync 配合 CancellationToken。
  2. 前端輪詢 / SignalR 接收 STATS 進度事件(需 CLR 整合或自訂擴充事件)。
  3. 或採用 SQL Server Agent 作業 + 網頁觸發/查詢作業狀態,完全脫離網頁請求生命週期。

此功能屬高風險操作,**務必加上詳細稽核日誌、操作確認對話框、權限管控**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved