信息系統是數據密集型的,數據的套賬,備份,還原是客戶最但願有的功能,這一節課就討論下C/S系統下數據庫的異步備份和還原,B/S系統的數據備份和還原和這個相似。
既然是異步,首先會想到使用多線程技術。.NET平臺提供了一整套的線程處理技術,使用線程的好處是,可讓一個線程作一件事情,多個線程之間根據時間片機制搶奪CPU和I/O資源,UI線程用於繪製界面,保證界面永遠對客戶的響應,而工做線程用於計算工做。
除了從頭開發線程外,.NET也提供了一個封裝好的線程組件BackgroundWorker,該組件讓您可以在應用程序的主要 UI 線程之外的其餘線程上異步(「在後臺」)執行耗時的操做。好比耗時耗資源的經常使用操做以下:
· 圖像下載
· Web 服務調用
· 文件下載和上載(包括點對點應用程序)
· 複雜的本地計算
· 數據庫事務
· 本地磁盤訪問(相對於內存訪問來講其速度很慢)
相似這樣的操做可能致使用戶界面在操做運行時掛起。若是須要用戶界面的響應卻遇到與此類操做關聯的長時間延遲,BackgroundWorker組件能夠提供一種方便的解決方案。若要使用 BackgroundWorker,只須要告訴該組件要在後臺執行的耗時的輔助方法,而後調用 RunWorkerAsync 方法。在輔助方法以異步方式運行的同時,您的調用線程繼續正常運行。該方法運行完畢,BackgroundWorker激發 RunWorkerCompleted 事件(可選擇包含操做結果)向調用線程發出警報。
「組件」選項卡的「工具箱」中提供了 BackgroundWorker組件。VS2005,VS2008, VS2010都有這個組件,以下圖:
若要向窗體添加 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 事件來完成的。
異步備份數據庫的代碼以下:
- //啓動備份
- private void btnBackUp_Click(object sender, EventArgs e)
- {
- try
- {
- SaveFileDialog sfd = new SaveFileDialog();
- sfd.Title = "請選擇備份保存的目錄";
- sfd.Filter = "(*.Bak)|*.Bak;|(All Files)|*.*";
- if (sfd.ShowDialog() == DialogResult.OK && sfd.FileName != string.Empty)
- {
- string filePath = sfd.FileName;
- //啓動異步備份,開始執行DoWork事件
- this.backgroundWorker1.RunWorkerAsync(new string[] { filePath, "InstallationsManager" });
- }
- }
- catch (System.Exception ex)
- {
- MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- //備份數據庫
- private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
- {
- try
- {
- using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["LongXiConnectionString"].ConnectionString))
- {
- con.Open();
- //彙報進度
- this.backgroundWorker1.ReportProgress(20);
- string[] args = (string[])e.Argument;
- string filePath = args[0];
- SqlCommand cmd = new SqlCommand();
- cmd.Connection = con;
- //備份數據庫
- cmd.CommandText = "use master;backup database " + args[1] + " to disk = '" + filePath + "' ";
- cmd.ExecuteNonQuery();
- this.backgroundWorker1.ReportProgress(60);
- //線程完成時返回的信息
- e.Result = "備份數據成功!";
- //this.label5.Text = "aaaaaaaa"; //Control.CheckForIllegalCrossThreadCalls = false
- this.backgroundWorker1.ReportProgress(100);
- }
- }
- catch (System.Exception ex)
- {
- MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- //線程執行完成後的收尾工做
- private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
- {
- try
- {
- if (e.Error != null)
- {
- MessageBox.Show("異常:" + e.Error.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- else if (e.Cancelled)
- {
- MessageBox.Show("線程已經退出!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- else
- {
- //MessageBox.Show(e.Result.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- //向UI提示備份數據庫成功
- this.lblInfo.Text = e.Result.ToString();
- }
- }
- catch (System.Exception ex)
- {
- MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- //向UI線程彙報進度,使進度條的值增長
- private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
- {
- try
- {
- this.pbarBackUp.Value = e.ProgressPercentage;
- }
- catch (System.Exception ex)
- {
- MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
和備份相似,這裏再也不講解,代碼以下:
- //啓動還原
- private void btnRestore_Click(object sender, EventArgs e)
- {
- //第一次後悔藥
- if (MessageBox.Show("該操做將數據覆蓋!若是選擇[是],將原來的數據覆蓋;若是選擇[否],將取消恢復.", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
- return;
- //第二次後悔藥
- if (MessageBox.Show("請再次確認,該操做不能恢復!若是選擇[是],將原來的數據覆蓋;若是選擇[否],將取消恢復.", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
- return;
- //沒得後悔藥吃了,開始執行還原
- try
- {
- OpenFileDialog ofd = new OpenFileDialog();
- ofd.Title = "請選擇要恢復的備份文件";
- ofd.Filter = "(*.Bak)|*.Bak;|(All Files)|*.*";
- if (ofd.ShowDialog() == DialogResult.OK && ofd.FileName != string.Empty)
- {
- string filePath = ofd.FileName;
- //啓動異步還原,開始執行DoWork事件
- this.backgroundWorker1.RunWorkerAsync(new string[] { filePath, "InstallationsManager" });
- }
- }
- catch (System.Exception ex)
- {
- MessageBox.Show("異常:" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- //還原數據庫
- private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
- {
- this.backgroundWorker1.ReportProgress(30);
- using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["LongXiConnectionString"].ConnectionString))
- {
- con.Open();
- //彙報進度
- this.backgroundWorker1.ReportProgress(20);
- Thread.Sleep(1000);
- string[] args = (string[])e.Argument;
- string filePath = args[0];
- SqlCommand cmd = new SqlCommand();
- this.backgroundWorker1.ReportProgress(30);
- Thread.Sleep(1000);
- this.backgroundWorker1.ReportProgress(60);
- cmd.Connection = con;
- //還原數據庫
- cmd.CommandText = "use master;alter database " + args[1] + " set offline with rollback immediate;restore database " + args[1] + " from disk = '" + filePath + "' with replace";
- cmd.ExecuteNonQuery();
- this.backgroundWorker1.ReportProgress(80);
- Thread.Sleep(1000);
- this.backgroundWorker1.ReportProgress(100);
- //線程完成時返回的信息
- e.Result = "恢復數據成功!";
- }
- }
- //彙報進度,使進度條的值增長
- private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
- {
- this.pbarRestore.Value = e.ProgressPercentage;
- }
- //線程執行完成後的收尾工做
- private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
- {
- if (e.Error != null)
- {
- MessageBox.Show("異常:" + e.Error.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- else if (e.Cancelled)
- {
- MessageBox.Show("線程已經退出!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- else
- {
- //MessageBox.Show(e.Result.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- //向UI提示恢復數據庫成功
- this.lblInfo.Text = e.Result.ToString();
- }
- }