您的位置:首页 > 数据库

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

2010-06-18 17:19 330 查看
信息系统是数据密集型的,数据的套帐,备份,还原是客户最希望有的功能,这一节课就讨论下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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息