異步備份和還原數據庫:C#.NET發現之旅

信息系統是數據密集型的,數據的套帳,備份,還原是客戶最希望有的功能,這一節課就討論下C/S系統下數據庫的異步備份和還原,B/S系統的數據備份和還原和這個類似。

既然是異步,首先會想到使用多線程技術。.NET平臺提供了一整套的線程處理技術,使用線程的好處是,可以讓一個線程做一件事情,多個線程之間根據時間片機制搶奪CPUI/O資源,UI線程用於繪製界面,保證界面永遠對客戶的響應,而工作線程用於計算工作。

除了從頭開發線程外,.NET也提供了一個封裝好的線程組件BackgroundWorker該組件讓您能夠在應用程序的主要 UI 線程以外的其他線程上異步(在後臺)執行耗時的操作。比如耗時耗資源的常用操作如下:

·         圖像下載

·         Web 服務調用

·         文件下載和上載(包括點對點應用程序)

·         複雜的本地計算

·         數據庫事務

·         本地磁盤訪問(相對於內存訪問來說其速度很慢)

類似這樣的操作可能導致用戶界面在操作運行時掛起。如果需要用戶界面的響應卻遇到與此類操作關聯的長時間延遲,BackgroundWorker組件可以提供一種方便的解決方案。若要使用 BackgroundWorker,只需要告訴該組件要在後臺執行的耗時的輔助方法,然後調用 RunWorkerAsync 方法。在輔助方法以異步方式運行的同時,您的調用線程繼續正常運行。該方法運行完畢,BackgroundWorker激發 RunWorkerCompleted 事件(可選擇包含操作結果)向調用線程發出警報。

組件選項卡的工具箱中提供了 BackgroundWorker組件。VS2005VS2008VS2010都有這個組件,如下圖:

若要向窗體添加 BackgroundWorker,請將 BackgroundWorker組件拖到窗體上即可。

若要啓動異步操作,請使用 RunWorkerAsync 方法。RunWorkerAsync 採用一個可選的 object 參數,可以使用該參數將變量傳遞給輔助方法。BackgroundWorker類公開 DoWork 事件,您的輔助線程通過 DoWork 事件處理程序附加到該事件。

 

BackgroundWorker包含三個主要的事件:

1,DoWork 事件

調用 RunWorkerAsync 方法時將引發此事件。在此,您就可以啓動操作來執行可能很耗時的工作。

2, RunWorkerCompleted 事件

DoWork事件處理程序返回時將引發此事件。如果操作成功完成,並且其結果在 DoWork事件處理程序中進行了分配,則可以通過RunWorkerCompletedEventArgs.Result屬性訪問該結果。

3, ProgressChanged 事件

調用 ReportProgress 方法時將引發此事件。ProgressChanged事件向用戶報告異步操作的進度

 

熟悉了組建用法後,開始做異步的數據庫備份和還原

一,異步數據庫備份,界面如下:

點擊開始備份按鈕,選擇一個文件夾保存備份文件

然後開始備份,線程會不停的彙報它自己執行的進度,用一個進度條來接受線程的進度,這個是通過ProgressChanged 事件完成的。

當備份完成後,線程會通知系統,它已經返回。如果中間線程出現執行錯誤,通過程序來捕獲。這個是通過RunWorkerCompleted 事件來完成的,而備份任務是通過DoWork 事件來完成的。

異步備份數據庫的代碼如下:

  1. //啓動備份  
  2. private void btnBackUp_Click(object sender, EventArgs e)  
  3. {  
  4.  
  5.     try 
  6.     {  
  7.         SaveFileDialog sfd = new SaveFileDialog();  
  8.         sfd.Title = "請選擇備份保存的目錄";  
  9.         sfd.Filter = "(*.Bak)|*.Bak;|(All Files)|*.*";  
  10.         if (sfd.ShowDialog() == DialogResult.OK && sfd.FileName != string.Empty)  
  11.         {  
  12.             string filePath = sfd.FileName;  
  13.             //啓動異步備份,開始執行DoWork事件  
  14.             this.backgroundWorker1.RunWorkerAsync(new string[] { filePath, "InstallationsManager" });  
  15.         }  
  16.     }  
  17.     catch (System.Exception ex)  
  18.     {  
  19.         MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  20.     }  
  21. }  
  22.  
  23. //備份數據庫  
  24. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)  
  25. {  
  26.     try 
  27.     {  
  28.         using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["LongXiConnectionString"].ConnectionString))  
  29.         {  
  30.             con.Open();  
  31.             //彙報進度  
  32.             this.backgroundWorker1.ReportProgress(20);  
  33.             string[] args = (string[])e.Argument;  
  34.             string filePath = args[0];  
  35.             SqlCommand cmd = new SqlCommand();  
  36.             cmd.Connection = con;  
  37.             //備份數據庫  
  38.             cmd.CommandText = "use master;backup database " + args[1] + " to disk = '" + filePath + "' ";  
  39.             cmd.ExecuteNonQuery();  
  40.             this.backgroundWorker1.ReportProgress(60);  
  41.             //線程完成時返回的信息  
  42.             e.Result = "備份數據成功!";  
  43.             //this.label5.Text = "aaaaaaaa"; //Control.CheckForIllegalCrossThreadCalls = false  
  44.             this.backgroundWorker1.ReportProgress(100);  
  45.         }  
  46.     }  
  47.     catch (System.Exception ex)  
  48.     {  
  49.         MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  50.     }  
  51.  
  52. }  
  53.  
  54. //線程執行完成後的收尾工作  
  55. private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
  56. {  
  57.     try 
  58.     {  
  59.         if (e.Error != null)  
  60.         {  
  61.             MessageBox.Show("異常:" + e.Error.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  62.         }  
  63.         else if (e.Cancelled)  
  64.         {  
  65.             MessageBox.Show("線程已經退出!""提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  66.         }  
  67.         else 
  68.         {  
  69.             //MessageBox.Show(e.Result.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  70.             //向UI提示備份數據庫成功  
  71.             this.lblInfo.Text = e.Result.ToString();  
  72.         }  
  73.     }  
  74.     catch (System.Exception ex)  
  75.     {  
  76.         MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  77.     }  
  78. }  
  79. //向UI線程彙報進度,使進度條的值增加  
  80. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)  
  81. {  
  82.     try 
  83.     {  
  84.         this.pbarBackUp.Value = e.ProgressPercentage;  
  85.     }  
  86.     catch (System.Exception ex)  
  87.     {  
  88.         MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  89.     }  

 二,異步還原數據庫

和備份類似,這裏不再講解,代碼如下:

 

  1. //啓動還原  
  2.      private void btnRestore_Click(object sender, EventArgs e)  
  3.      {  
  4.          //第一次後悔藥  
  5.          if (MessageBox.Show("該操作將數據覆蓋!如果選擇[是],將原來的數據覆蓋;如果選擇[否],將取消恢復.""提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)  
  6.              return;  
  7.          //第二次後悔藥  
  8.          if (MessageBox.Show("請再次確認,該操作不能恢復!如果選擇[是],將原來的數據覆蓋;如果選擇[否],將取消恢復.""提示", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)  
  9.              return;  
  10.          //沒得後悔藥吃了,開始執行還原  
  11.          try 
  12.          {  
  13.              OpenFileDialog ofd = new OpenFileDialog();  
  14.              ofd.Title = "請選擇要恢復的備份文件";  
  15.              ofd.Filter = "(*.Bak)|*.Bak;|(All Files)|*.*";  
  16.              if (ofd.ShowDialog() == DialogResult.OK && ofd.FileName != string.Empty)  
  17.              {  
  18.                  string filePath = ofd.FileName;  
  19.                  //啓動異步還原,開始執行DoWork事件  
  20.                  this.backgroundWorker1.RunWorkerAsync(new string[] { filePath, "InstallationsManager" });   
  21.              }  
  22.          }  
  23.          catch (System.Exception ex)  
  24.          {  
  25.              MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  26.          }  
  27.      }  
  28.  
  29.      //還原數據庫  
  30.      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)  
  31.      {  
  32.          this.backgroundWorker1.ReportProgress(30);  
  33.          using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["LongXiConnectionString"].ConnectionString))  
  34.          {  
  35.              con.Open();  
  36.              //彙報進度  
  37.              this.backgroundWorker1.ReportProgress(20);  
  38.              Thread.Sleep(1000);  
  39.              string[] args = (string[])e.Argument;  
  40.              string filePath = args[0];  
  41.              SqlCommand cmd = new SqlCommand();  
  42.              this.backgroundWorker1.ReportProgress(30);  
  43.              Thread.Sleep(1000);  
  44.              this.backgroundWorker1.ReportProgress(60);  
  45.              cmd.Connection = con;  
  46.              //還原數據庫  
  47.              cmd.CommandText = "use master;alter database " + args[1] + "  set offline with rollback immediate;restore database " + args[1] + " from disk = '" + filePath + "'  with replace";  
  48.              cmd.ExecuteNonQuery();  
  49.              this.backgroundWorker1.ReportProgress(80);  
  50.              Thread.Sleep(1000);  
  51.              this.backgroundWorker1.ReportProgress(100);  
  52.              //線程完成時返回的信息  
  53.              e.Result = "恢復數據成功!";  
  54.          }  
  55.      }  
  56.      //彙報進度,使進度條的值增加  
  57.      private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)  
  58.      {  
  59.          this.pbarRestore.Value = e.ProgressPercentage;  
  60.      }  
  61.      //線程執行完成後的收尾工作  
  62.      private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
  63.      {  
  64.          if (e.Error != null)  
  65.          {  
  66.              MessageBox.Show("異常:" + e.Error.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);  
  67.          }  
  68.          else if (e.Cancelled)  
  69.          {  
  70.              MessageBox.Show("線程已經退出!""提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  71.          }  
  72.          else 
  73.          {  
  74.              //MessageBox.Show(e.Result.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  75.              //向UI提示恢復數據庫成功  
  76.              this.lblInfo.Text = e.Result.ToString();  
  77.          }  
  78.      } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章