首页 > 代码库 > 异步备份和还原数据库:.NET发现之旅(六)

异步备份和还原数据库:.NET发现之旅(六)

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://terryli.blog.51cto.com/704315/335062

信息系统是数据密集型的,数据的套帐,备份,还原是客户最希望有的功能,这一节课就讨论下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 事件来完成的。

 

 

异步备份数据库的代码如下:

 

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

异步备份和还原数据库:.NET发现之旅(六)