当前位置: 首页 > news >正文

异步备份和还原数据库:.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.      } 

 

相关文章:

  • 【转载】一位大学老师写给即将毕业的大学生的100条忠告
  • GPON故障总结(四)
  • Css Hack
  • windows7下Windows Live Messenger 托盘问题
  • 图解Windows xp—FTP服务器配置
  • [经验总结] 关于单元测试
  • 我的OSPF学习笔记
  • 软件项目经理应有的能力和素质
  • 动态创建GridView的列(第二部分)
  • visual studio数据集dataset.xsd文件使用
  • java反射总结
  • 临 元 刘堪 《蔬林远山图》
  • Linux系统配置VI或VIM的技巧
  • 对Excel中边框(Border)的理解
  • 神奇.NET之旅2
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 【个人向】《HTTP图解》阅后小结
  • ES6 ...操作符
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • node 版本过低
  • REST架构的思考
  • storm drpc实例
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • 分享一份非常强势的Android面试题
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 使用putty远程连接linux
  • 微信开源mars源码分析1—上层samples分析
  • 写代码的正确姿势
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 7行Python代码的人脸识别
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​插件化DPI在商用WIFI中的价值
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • ​业务双活的数据切换思路设计(下)
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #pragma 指令
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (2)(2.10) LTM telemetry
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (Python) SOAP Web Service (HTTP POST)
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (二)JAVA使用POI操作excel
  • (二十三)Flask之高频面试点
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (转载)Linux 多线程条件变量同步
  • .gitignore文件设置了忽略但不生效
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .Net Core缓存组件(MemoryCache)源码解析
  • .net core控制台应用程序初识