zoukankan      html  css  js  c++  java
  • C#可定制的数据库备份和恢复程序 (讲解流程)

    可定制的数据库备份和恢复程序 tashanzhishi [原作]
    关键字 数据库 备份 恢复
    出处

    在我们做数据库系统的程序时,经常需要为客户做一个数据库的备份和恢复程序,特别是对于一些非专业的数据库用户,这个程序更是必不可少,而且操作必需足够简单。因为在很多系统中,数据库的备份恢复功能都是相近的,因此,我们最好做一个通用的数据库备份恢复程序,这样就不必每个系统都开发一套了。

    要开发这样一套系统,我个人认为应该满足以下要求:
    1. 备份恢复操作应该有历史记录(必需有一个备份列表,列出备份文件的相关信息),便于用户查找以往的备份。
    2. 对于每一次备份和恢复应允许用户记录备份和恢复的原因。
    3. 系统应允许用户进行简单的配置,并且配置可以保存。
    4. 备份和恢复应该足够简单,最好类似与文件的复制,对于已经进行的备份,应允许用户从备份列表恢复。
    5. 即使因为某种原因使要恢复的数据库正在占用,也应该允许用户恢复(这一点很重要,因为你不能指望用户自己保证数据库的独占性)。
    6. 实时显示备份或恢复的当前进度。
    要达到以上的要求,我想我们应该这样设计系统:
    1. 对于每一次的数据库备份和恢复,我们都记下当时的数据库服务器名,数据库名,备份文件全路径名,备份时间,进行备份或恢复的原因等信息,并把这些信息以XML的形式保存,下面是我得一个备份文件实例:
    <?xml version="1.0" encoding="GB2312"?>
    <history>
    <bak>
    <time>20040205 10:41:21</time>
    <dbname>hrmjx4</dbname>
    <des>测试备份</des>
    <path>E: icatex2003.bak</path>
    </bak>
    <bak>
    <time>20040205 10:43:58</time>
    <dbname>hrmjx4</dbname>
    <des>每周例行备份</des>
    <path>E:hrmjx4040205.bak</path>
    </bak>
    </history>
    2. 对于用户的配置可以这样进行:
    <?xml version="1.0" encoding="GB2312"?>
    <set>
    <appname>数据库备份</appname>
    <bakcount>20</bakcount>
    <servername>.</servername>
    <dbname>book</dbname>
    <username>sa</username>
    <password>2iUc94tkpsg=</password>
    </set>
    上面依次记录了备份程序的名称(显示在备份窗体的标题栏,无实际用处),备份历史最大记录数,备份的数据库服务器名称,备份的数据库名称,用户名,密码(已经过加密)等信息。我们在程序刚开始启动时,就自动把这些信息应用到用户界面上去,这样就不用用户重新设置了。
    3. 备份时我们采取直接备份到文件的方法,用户只需使用保存文件对话框指定要备份的位置和文件名即可,其余的工作通过程序完成,恢复也一样,只需通过打开文件对话框指定从其中恢复的文件即可。
    4. 我们在恢复时,先杀死要恢复的数据库所关联的所有用户线程,然后再进行恢复,这样就不会存在因为数据库独占性引起的恢复错误。
    5. 对于实时显示备份和恢复的进度问题,我们采取SQL-DMO的回调函数的方式实现。

    下面是相关技术难点的代码实现(因为个人的喜好,在此已C#的代码形式实现):
    1. 在用户的配置时,我们需要列出当前局域网内所有的数据库服务器,并且要列出指定服务器的所有数据库,实现代码如下:
    取得数据库服务器列表:
    public ArrayList GetServerList()
    {
    ArrayList alServers = new ArrayList() ;
    SQLDMO.Application sqlApp = new SQLDMO.ApplicationClass() ;
    try
    {
    SQLDMO.NameList serverList = sqlApp.ListAvailableSQLServers() ;
    for(int i = 1;i<= serverList.Count;i++)
    {
    alServers.Add(serverList.Item(i)) ;
    }
    }
    catch(Exception e)
    {
    throw(new Exception("取数据库服务器列表出错:"+e.Message)) ;
    }
    finally
    {
    sqlApp.Quit() ;
    }
    return alServers ;
    }
    取得指定数据库服务器的数据库列表
    public ArrayList GetDbList(string strServerName,string strUserName,string strPwd)
    {
    ServerName = strServerName ;
    UserName = strUserName ;
    Password = strPwd ;

    ArrayList alDbs = new ArrayList() ;
    SQLDMO.Application sqlApp = new SQLDMO.ApplicationClass() ;
    SQLDMO.SQLServer svr = new SQLDMO.SQLServerClass() ;
    try
    {
    svr.Connect(ServerName,UserName,Password) ;
    foreach(SQLDMO.Database db in svr.Databases)
    {
    if(db.Name!=null)
    alDbs.Add(db.Name) ;
    }
    }
    catch(Exception e)
    {
    throw(new Exception("连接数据库出错:"+e.Message)) ;
    }
    finally
    {
    svr.DisConnect() ;
    sqlApp.Quit() ;
    }
    return alDbs ;
    }

    2. 数据库的备份和实时进度显示代码:
    public bool BackUPDB(string strDbName,string strFileName, ProgressBar pgbMain)
    {
    PBar = pgbMain ;
    SQLDMO.SQLServer svr = new SQLDMO.SQLServerClass() ;
    try
    {
    svr.Connect(ServerName,UserName,Password) ;
    SQLDMO.Backup bak = new SQLDMO.BackupClass();
    bak.Action = 0 ;
    bak.Initialize = true ;
    SQLDMO.BackupSink_PercentCompleteEventHandler pceh = new SQLDMO.BackupSink_PercentCompleteEventHandler(Step);
    bak.PercentComplete += pceh;

    bak.Files = strFileName;
    bak.Database = strDbName;
    bak.SQLBackup(svr);
    return true ;
    }
    catch(Exception err)
    {
    throw(new Exception("备份数据库失败"+err.Message)) ;
    }
    finally
    {
    svr.DisConnect() ;
    }
    }

    private void Step(string message,int percent)
    {
    PBar.Value = percent ;
    }
    其中,这两个语句实现了进度的实时显示:
    SQLDMO.BackupSink_PercentCompleteEventHandler pceh = new SQLDMO.BackupSink_PercentCompleteEventHandler(Step);
    bak.PercentComplete += pceh;
    Step就是上面private void Step(string message,int percent) 的方法名称,它用来显示进度条的当前进度。

    3. 数据库的恢复和杀死进程的代码:
    public bool RestoreDB(string strDbName,string strFileName, ProgressBar pgbMain)
    {
    PBar = pgbMain ;
    SQLDMO.SQLServer svr = new SQLDMO.SQLServerClass() ;
    try
    {
    svr.Connect(ServerName,UserName,Password) ;
    SQLDMO.QueryResults qr = svr.EnumProcesses(-1) ;
    int iColPIDNum = -1 ;
    int iColDbName = -1 ;
    for(int i=1;i<=qr.Columns;i++)
    {
    string strName = qr.get_ColumnName(i) ;
    if (strName.ToUpper().Trim() == "SPID")
    {
    iColPIDNum = i ;
    }
    else if (strName.ToUpper().Trim() == "DBNAME")
    {
    iColDbName = i ;
    }
    if (iColPIDNum != -1 && iColDbName != -1)
    break ;
    }

    for(int i=1;i<=qr.Rows;i++)
    {
    int lPID = qr.GetColumnLong(i,iColPIDNum) ;
    string strDBName = qr.GetColumnString(i,iColDbName) ;
    if (strDBName.ToUpper() == strDbName.ToUpper())
    svr.KillProcess(lPID) ;
    }

    SQLDMO.Restore res = new SQLDMO.RestoreClass() ;
    res.Action = 0 ;
    SQLDMO.RestoreSink_PercentCompleteEventHandler pceh = new SQLDMO.RestoreSink_PercentCompleteEventHandler(Step);
    res.PercentComplete += pceh;
    res.Files = strFileName ;

    res.Database = strDbName ;
    res.ReplaceDatabase = true ;
    res.SQLRestore(svr) ;
    return true ;
    }
    catch(Exception err)
    {
    throw(new Exception("恢复数据库失败,请关闭所有和该数据库连接的程序!"+err.Message)) ;
    }
    finally
    {
    svr.DisConnect() ;
    }
    }

    其中这个语句取得了所有的进程列表:
    SQLDMO.QueryResults qr = svr.EnumProcesses(-1) ;
    下面的语句找到和要恢复数据库相关的进程并杀死:
    int iColPIDNum = -1 ;
    int iColDbName = -1 ;
    for(int i=1;i<=qr.Columns;i++)
    {
    string strName = qr.get_ColumnName(i) ;
    if (strName.ToUpper().Trim() == "SPID")
    {
    iColPIDNum = i ;
    }
    else if (strName.ToUpper().Trim() == "DBNAME")
    {
    iColDbName = i ;
    }
    if (iColPIDNum != -1 && iColDbName != -1)
    break ;
    }

    for(int i=1;i<=qr.Rows;i++)
    {
    int lPID = qr.GetColumnLong(i,iColPIDNum) ;
    string strDBName = qr.GetColumnString(i,iColDbName) ;
    if (strDBName.ToUpper() == strDbName.ToUpper())
    svr.KillProcess(lPID) ;

  • 相关阅读:
    父子进程 signal 出现 Interrupted system call 问题
    一个测试文章
    《淘宝客户端 for Android》项目实战 html webkit android css3
    Django 中的 ForeignKey ContentType GenericForeignKey 对应的数据库结构
    coreseek 出现段错误和Unigram dictionary load Error 新情况(Gentoo)
    一个 PAM dbus 例子
    漫画统计学 T分数
    解决 paramiko 安装问题 Unable to find vcvarsall.bat
    20141202
    js
  • 原文地址:https://www.cnblogs.com/meimao5211/p/3339898.html
Copyright © 2011-2022 走看看