快速,持续,稳定,傻瓜式
支持Mysql,Sqlserver数据同步

MySQL数据库备份实用程序

在线QQ客服:1922638

专业的SQL Server、MySQL数据库同步软件

介绍

论坛上最常见的问题之一是如何直接从.NET应用程序备份MySql数据库。不幸的是,与Access,SqlLite等不同,它并不是仅复制文件并重命名的情况,实际上,您必须精打细算并基本上重新创建创建所有表并将所有数据从头插入表中的SQL。 。显然,有一些应用程序可以为您执行此操作,例如SqlDump,mysqlhotcopy等,但是这些应用程序通常需要一些MySQLl和关系数据库的知识。不幸的是,根据我的经验,我99%的客户甚至不知道什么是关系数据库。他们只想要一个计算机程序,可以执行发票并使用漂亮的图形来管理库存。谈到备份,他们只想按一个说“备份”的按钮,一切都已做好。对此的明显答案是使用Process.Start("mysqldump", filename),请记住,您已完成完整备份。可悲的是,我从未在此方面取得太大成功。让我告诉你。我尝试过,但是它总是会塞满东西,尤其是当客户试图进行备份而没有其他人为他们恢复过程时。然后,您会遇到一个愤怒的客户,告诉您您具有精明的编程能力,甚至无法使备份系统正常工作。因此,我着手制作一个可以在.NET应用程序中使用的防弹,完全托管的备份类。

我只是认为,在完成了我打算完成的大部分工作之后,我将与其他需要类似东西的人分享这项努力的结果。首先,我需要强调一点,我绝不是数据库专家,而是一个谦虚的应用程序开发人员,他建立了业务,构建的定制业务应用程序恰好有一个后端数据库。虽然我已经在自己的数据库上成功进行了全面测试,但是这些数据库往往很小,位于执行备份的计算机上。对于在那里的数据库专家,我非常感谢您的评论和批评,以优化此问题并纠正我做错的事情。如果代码行太长而无法滚动阅读,我也需要提前道歉。我有宽屏显示器,

先决条件

除了您需要访问带有数据库的MySQL服务器以及可以在此处找到的MySQL的.NET连接器:MySql Connector for .NET之外,您只需要Visual Studio(我使用过VS 2008年)来运行项目并测试备份。

项目设计

显然,一旦确定了项目打算做什么,首先要做的就是弄清楚实现这些目标所必需的。在备份数据库架构时,唯一要做出决定的事情是:

1.从头开始重新创建数据库的最佳方法是什么?

完成研究之后,主要研究其他人和组织的完成方式,我得出的结论是CREATEINSERT为每个表的s和s 重新创建SQL 是最明显的方法,尤其是因为这是我们原始的结论。我们还需要决定重新创建数据库所需的时间。我们是否需要备份存储过程,函数和视图?那重新创建索引呢?和外键?

我决定最好以能够重新创建任何数据库(包括存储过程,函数,视图和外键)为目标。就索引而言,当还原时重新创建表时,我将依靠MySQL本身自动在唯一,主键和外键上创建索引。恢复完成后,SysAdmin必须手动创建任何其他索引。

2.存储由备份创建的SQL语句的最佳方法是什么?

这里最明显的选择是一个简单的文本文件,该文件可以作为流读取,并且可以动态分析SQL。但这引发了关于如何分隔表,存储过程等不同部分的问题,因为您将需要使用正则表达式,某种逗号分隔符或某种方式来查找恢复过程中的位置。此选项还引发了有关如何确保数据完整性以及如何验证选择用于还原的备份文件的问题。

我想到的解决方案是使用XML文件格式。这就解决了上面所有的问题,因为您可以使用XML标记将各部分分开而没有任何麻烦,并且使用XML属性,不仅可以还原整个数据库,还可以还原所需的位。该解决方案还解决了所有验证问题,因为您可以创建一个XML模式,即使用户选择该模式也可以用来验证整个文件。当我使用VB.NET创建类时,我也可以使用LINQ和XML文字(抱歉,C#专家-您将不得不等待.NET 5.0)来相对轻松地创建和读取XML文件。非常感谢Jorge Paulino撰写的有关XML文字的文章,因为我之前从未听说过它们。这种方法的另一个优点是,由于XML是国际标准,即使没有创建文件的应用程序,重新创建数据库也相对容易。即使只是在记事本中打开,也很容易看到数据库和数据的结构。

3.如何完成创建SQL并将其保存在XML文件中的实际操作?

主要目标之一是确保我们可以在所有数据库项目中重用此代码,因此唯一的方法是创建一个独立的类库,可以在需要时将其导入任何其他项目中。然后,问题就变成了是拥有一个既处理备份又还原的类,还是拥有两个类,一个用于备份,一个用于还原。我选择了两个单独的类,主要是因为我可以为每个类使用相同的构造函数,但仍然知道它是还原还是备份。我包括一个处理XML创建和验证的模块。该模块还包括用于验证与服务器的连接的功能,以及用于返回特定用户有权在所选服务器上查看的数据库列表的功能。

备份类

这个怎么运作

BackUp班有三个私有变量:一ConnectionStringBuilder来保存我们的服务器和用户信息,并且还构建了连接字符串中的各种备份程序; 一个XDocument(仅是XML文件在内存中的表示形式),以构造备份文件(我任意给了这些文件扩展名.msb [MySQL Backup-我认为非常原始]);和一个将保存要保存的备份文件的完整路径名的字符串。该类具有一个构造函数和一个公开的方法- BackUpDataBase(再次具有我的独创性)。构造函数四根弦作为参数,即UserNamePasswordDataBase,和FileName,这些都是不言自明。它使用这些参数来实例化ConnectionStringBuilder并指定路径名。构造函数还调用Validation Module中的方法,该方法BuildNewBackUpFile将创建一个全新的.msb文件。此方法建立了一个XDocument使用XML的文字,然后返回该文档。

Friend Function BuildNewBackUpFile() As XDocument
    'You just gotta love these XML literals dontcha 
    Dim NewXDoc As New XDocument  wXDoc = <?xml version="1.0" encoding="UTF-8"?> 
              <!--MySql Backup File-->
              <DataBase>
                 <Tables></Tables>
                 <Constraints></Constraints>
                 <Inserts></Inserts>
                 <Views></Views>
                 <Procedures></Procedures>
                 <Functions></Functions>
                 <Events></Events>
                 <Triggers></Triggers>
              </DataBase>
    Return NewXDoc 'Easy as that 
  
End Function 'BuildNewBackUpFile

从例程中可以看到,它实际上是一个简单的布局。然后将各个部分保存在适当的标签下,如下所示:

<Tables>
 <Table Name="MyTableName">CREATE TABLE `Table1`(`ID`int(10),`Name`varchar(45))</Table>
 <Table Name="MyTableName2">CREATE TABLE`Table2`(`ID`int(10),`Name`varchar(45))</Table>
<Tables>
<Constraints>
 <Constraint Name="MyConstraint">ALTER TABLE `MyTable` _
                  ADD CONSTRAINT `MyConstraint`FOREIGN KEY (... etc <Constraint>
<Constraints>

BackUpDataBase例程

公开的方法BackUpDataBase采用可选BackGroundWorker参数作为参数,这使得在备份发生时很容易报告备份的进度。基本上,此例程所做的全部工作是依次调用每个单独的节,将不同的步骤分解为各自的例程。在每一个程序,我不会跟每一个细节来烦你,所有的人在本质上非常相似,所以我将通过两个最重要的程序:BackUpTablesCreateTable是的一个分支BackUpTables),和BackUpData

BackUpTables例程

该例程基本上使用Information_Schema数据库来查询属于所选数据库的所有表的名称,然后使用a DataReader来遍历这些表,调用该CreateTable例程来构建SQL以创建每个表。CREATE TABLE返回该语句后,例程将创建一个新的XElement来保存新的XML,将表名分配给标签的Name属性Table,并XElement在父节点下添加Tables

Dim newElement As New XElement("Table", strCreateTable) 
newElement.@Name = strTableName  'Set name attribute to Table Name
Dim parent As XElement = msbBackUp...<Tables>.FirstOrDefault
parent.Add(newElement) 'Add to Tables

然后,它BackUpData在每个表上调用例程,然后为Insert表中的每一行数据创建语句。使用相同的查询可为我们提供引擎类型和Next Auto_Increment标记到CREATE TABLE语句末尾的值。由于这是最耗时的阶段,因此例程可以选择以a BackGroundWorker作为参数,从而允许工作人员报告进度。仅当存在Worker时,才对Information_Schema.Tables表进行Count查询来计算此值。

CreateTable例程

该例程以表名,引擎类型Next Auto_Increment为参数,并建立并返回CREATE TABLE每个表的完整语句。最初,它从创建DROP TABLE语句开始,然后使用DESCRIBE TABLE查询来构造该CREATE TABLE语句,并遍历返回的每个字段。

Dim strReturn As String = "DROP TABLE IF EXISTS _
                                `" & strConnection.Database & "`.`" & Table & "`;"
Using conDetails As New MySqlConnection(strConnection.ToString) 
    strReturn &= "CREATE TABLE `" & strConnection.Database & "`.`" & Table & "` (" 
    Dim cmdRows As New MySqlCommand("DESCRIBE `" & Table & "`", conDetails) 
    Dim dbrRows As MySqlDataReader 
    conDetails.Open() 
    dbrRows = cmdRows.ExecuteReader()

查询Describe Table的表中的每一列返回六个值:Field(名称), Type(数据类型)NullKeyDefault,和Extra。收到此信息后,只需按以下顺序构建各列即可:Name DataType (max value) NOT NULL / NULL AUTO_INCREMENT。我们将分别构建一个主键,如果不为空,则将其标记到上Create Table。最后,我们Next Auto_Increment在语句末尾包含有关引擎类型和编号的信息,以确保恢复创建正确的表类型(如果未声明,MySQL默认为InnoDB)。

While dbrRows.Read() ' For each Field in table
    strReturn &= "`" & dbrRows.GetString("Field") & "` " & dbrRows.GetString("Type")
    If Not dbrRows.GetString("Null") = "YES" Then 
        strReturn &= " NOT NULL"
    End If
    If Not IsDBNull(dbrRows.Item("Default")) Then 
        strReturn &= " DEFAULT '" & dbrRows.GetString("Default") & "'"
    End If
    If Not dbrRows.GetString("Extra") = Nothing Then 
        strReturn &= " " & dbrRows.GetString("Extra").ToUpper() 
    End If
    If Not dbrRows.GetString("Key") = Nothing Then 
     If dbrRows.GetString("Key") = "PRI" Then 
         If strPrimaryBuilder = String.Empty Then
            strPrimaryBuilder = dbrRows.GetString("Field") 
         Else
            strPrimaryBuilder &= "," & dbrRows.GetString("Field")
         End If
     End If
    End If
    strReturn &= "," 'add comma between Fields
End While
If strPrimaryBuilder = String.Empty Then
   strReturn = strReturn.Remove(strReturn.Length - 1, 1)
Else
   strPrimaryKey = "PRIMARY KEY (" & strPrimaryBuilder & ")" 
End If
strReturn &= strPrimaryKey & ") " 
dbrRows.Close()
strReturn &= "ENGINE=" & TableEngine 
If AutoIncrement >= 0 Then
    strReturn &= " AUTO_INCREMENT=" & AutoIncrement

BackUpData例程

本节可能是所有内容的基础,而我们要做的只是SELECT *从表中调用查询,将此查询传递给阅读器,并Insert使用结果构建SQL语句。

Dim strInsert As String = String.Empty
Using conData As New MySqlConnection(strConnection.ToString)
  Dim cmdRows As New MySqlCommand("SELECT * FROM `" & _
                                   strConnection.Database & "`.`" _
                                   & Table & "`", conData)
  conData.Open()
  Dim dbrRows As MySqlDataReader = cmdRows.ExecuteReader
  If dbrRows.HasRows Then 'If no Data ...bugger off and get a coffee      

我发现必须检索每个值的数据类型,然后自己处理许多数据类型,因为诸如字符串中的撇号,MySQL / .NET日期转换等之类的事情实际上可能会突然使事情停顿。让我惊讶的一件事是需要将布尔值转换为整数,因为当保存布尔值时,它将按字面意义将其保存为True或False,然后在尝试还原时会说失败转换为布尔值。我需要弄清的一个重要方面是如何保存Blob列。最后,我通过将字节检索到字节数组中,然后将字节转换为十六进制,然后存储十六进制版本来进行破解。此功能适用于图片,Word,Excel和文本文件,可以完美还原所有文件(Excel会警告文件格式错误或其他问题,但是如果您忽略了它,只是告诉它继续进行,它将很好地打开)。由于我事先不知道blob字段的大小,因此我不得不用一个任意值(任意限制为1 MB)来启动字节数组。如果返回的文档或图片的尺寸可能大于此尺寸,则必须增加此尺寸。这也将严重取决于服务器能够将其作为结果集返回的最大数据大小,默认情况下,MySQL还将其设置为1 MB。在我专门创建的测试数据库上进行一些测试,在开始出现OutOfMemory异常之前(在具有2 GB内存的基本32位系统上),我可以将其扩展到15 MB。显然,这将使您在表中拥有的更多记录越来越少,请记住,这全部都存储在内存XML文件中,

While dbrRows.Read
  strInsert = "INSERT INTO `" & conData.Database & "`.`" & Table & "` (" 
  Dim intFieldCount As Integer = dbrRows.FieldCount - 1
  Dim columns As New List(Of String) 
  Dim values As New List(Of String) 
  For intColumns As Integer = 0 To intFieldCount 
      If Not IsDBNull(dbrRows(intColumns)) Then 
        columns.Add("`" & dbrRows.GetName(intColumns) & "`") 
        Dim strType As String = dbrRows.Item(intColumns).GetType.ToString 
        Select Case strType 
            Case "System.DateTime" l
                Dim dteValue As DateTime = dbrRows.GetMySqlDateTime(intColumns) 
                Dim strValue As String = "'" & dteValue.Year & "-" & _
                 dteValue.Month & "-" & _
                 dteValue.Day & "'"
                values.Add(strValue)
            Case "System.Boolean" 
                Dim intBoolean As Integer 
                If dbrRows.Item(intColumns) = True Then 
                                        intBoolean = 1
                Else
                                        intBoolean = 0
                End If
                values.Add(intBoolean.ToString)
            Case "System.String" 
                Dim strValue As String = dbrRows.GetString(intColumns)
                strValue = strValue.Replace("'", "''") 
                strValue = strValue.Replace(";", "") 
                values.Add("'" & strValue & "'")
            Case "System.Byte[]"  
                Dim bytBlob(1048576) As Byte  
                Dim lngFileLength As Long = _
                       dbrRows.GetBytes(intColumns, 0, bytBlob, 0, 1048576)
                ReDim Preserve bytBlob(lngFileLength) 
                values.Add("0x" & ByteArrayToHex(bytBlob)) 
            Case Else 'Otherwise
                If IsNumeric(dbrRows.Item(intColumns)) Then
                    values.Add(dbrRows.Item(intColumns))
                Else
                    values.Add("'" & dbrRows.Item(intColumns).ToString & "'")
                End If
       End Select
     End If
  Next
  strInsert &= Join(columns.ToArray, ", ") & ") " & "VALUES ( " 
  strInsert &= Join(values.ToArray, ", ") & " )"

一旦INSERT语句结束,则再向前走,并在标签下创建一个XML元素<Inserts>,与标签<Insert>如上所述。

备份约束,视图,过程和函数

上述每个部分都有其自己的例程,例如BackUpConstraintsBackUpViews等等,并且每个例程本质上非常相似。基本上,他们都查询INFORMATION_SCHEMA数据库通过每一个找到的值,并调用检索与当前数据库相关的实体名称,然后循环SHOW CREATE FUNCTIONSHOW CREATE PROCEDURE等,视情况而定。然后,该调用的结果传递给读取器,该读取器从右列检索值并建立XML元素,并将其添加到current中XDocument

完成备份

初始BackUpDataBase例程完成所有部分后,只需调用XDocumentSave方法即可完成备份。

恢复课程

这个怎么运作

Restore类只有两个私有变量,即ConnectionStringBuilderXDocument。该类的构造函数采用五个参数:用户名,密码,服务器,数据库以及要还原的文件的完整路径。与BackUp类一样,构造函数使用这些参数实例化,ConnectionStringBuilderXDocument使用XDocument.Load(FileName)方法将变量设置为正确的文件。该Restore班还有两个方法,一个方法来验证选定的备份文件包含有关选定的数据库信息,而另一个做所有的工作方法:RestoreDataBase(再次,额外的创意点)。

验证数据库

我包含了此例程,以确保用户为正确的数据库选择了正确的备份文件。它所做的只是检查Name附加到主数据库标记的属性是否与所选数据库的名称匹配。使用XML文字,这变得非常容易:

Public Function ValidateDataBases() As Boolean
 'Just checks whether the correct backup file for selected database are the same
 Dim strDataBaseName As String = msbRestoreFile...<DataBase>.@Name 
 If strDataBaseName = strConnection.Database Then
    Return True
 Else
    Return False
 End If
        
End Function

需要RestoreDatabase在用于实际还原的应用程序中进行主调用之前,先调用此函数,下面将在演示应用程序中进行解释。

RestoreDataBase

这个例程是整个班级的关键。它采用一个可选BackGroundWorker参数作为参数,以方便进度报告。基本上,此例程仅调用其他例程,这些例程实际上恢复了不同的相关部分。首先开始还原表,然后在还原实际数据之前重新创建所有外键和唯一键约束。通过这种方式,我认为在恢复数据时将针对所有约束条件对数据进行验证。从那里继续,然后重新创建所有功能,过程等(如果有)。由于所有不同的部分几乎都相同,因此我将仅介绍RestoreTablesRestoreData例程。

还原表

使用所有这些例程,我们仅使用LINQ和XML文字从备份文件的相关部分提取每个值,然后对数据库执行该值(这是一个完整的SQL语句)。在RestoreTables例程中,您可以看到我首先关闭了所有约束检查,因此删除具有外键约束的表时没有问题。使用XML文字和LINQ检索值的好处在于,如果没有值,则什么也不会发生。您不会收到任何错误,警告或任何内容,它只会转到下一部分(尽管我不太明白为什么有人会备份没有表的数据库)。

Private Sub RestoreTables()
    Using conTables As New MySqlConnection(strConnection.ToString)
        conTables.Open() 
        Dim cmdSetUp As New MySqlCommand(" _
                   SET _
                     @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;"&" _
                   SET _
                     @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, _
                     FOREIGN_KEY_CHECKS=0;", conTables)
        cmdSetUp.ExecuteNonQuery()
        For Each table In From element In msbRestoreFile...<Table> 
            Dim cmdCreateTable As New MySqlCommand(table.Value, conTables) 
            cmdCreateTable.ExecuteNonQuery()
        Next
    End Using

End Sub 'RestoreTables  

这是基本的程序,然后所有的恢复程序(RestoreConstraintsRestoreViews等),当它涉及到的除了RestoreData这里我用一个程序MySqlTransaction来执行InsertS,因为这样一来,总有回滚的选项,如果有问题, ,以及它快得多的事实。在所有其他情况下使用事务是适得其反,执行语句,例如当作为CREATE TABLECREATE FUNCTION等等,MySQL的一个隐含的承诺,所以交易是多余的。

恢复数据

我让此例程接受一个可选BackGroundWorker参数作为自变量,以便我们可以按进度报告进度。除了一些代码来计算有多远,我们在这个过程中,其他一切都是非常类似于之前已经上,除了我们用TryCatchEnd Try块捕获任何异常,如果是回滚事务。

Private Sub RestoreData(Optional ByVal worker As BackgroundWorker = Nothing)
    Using conData As New MySqlConnection(strConnection.ToString)
        Dim transData As MySqlTransaction
        conData.Open()
        transData = conData.BeginTransaction
        Try
            Dim intInsertCount As Integer = msbRestoreFile...<Insert>.Count
            Dim intInsertsMade As Integer = 0
            For Each insert In From element In msbRestoreFile...<Insert>
                If Not worker Is Nothing Then 
                   worker.ReportProgress(20 + ((70 / intInsertCount)*intInsertsMade))
                   intInsertsMade += 1
                End If
                Dim cmdData As New MySqlCommand(insert.Value, conData)
                cmdData.ExecuteNonQuery()
            Next
            transData.Commit()
        Catch exMySql As MySqlException
            If Not transData Is Nothing Then
                transData.Rollback()
            End If
            Throw exMySql
        End Try

如果遇到任何错误,那么我将回滚所有数据插入,但让其余过程继续进行。这样,数据库结构将在末尾就位,而不是恢复一半的表负载。在我所有的应用程序中,我都使用了一个相当不错的日志记录系统,该系统将针对数据库执行的所有SQL记录在一个单独的XML文件中,如果有必要,这可以用于重建自开始使用该程序以来的所有事务(非常困难)。进行,但可能)。由于需要进行最后一次备份,因此我也使用此日志来重新创建事务,因为上次备份已完成(通常是最近24小时)。

完成还原

重建表,重新创建约束并恢复数据至理想状态后,我们将以相同的方式继续还原其余的模式,功能,过程,视图等。然后就完成了,我认为客户现在会对我更加满意。

使用类-演示应用程序

应用程序

我包括的演示应用程序是一个非常基本的应用程序,它完成两件事-使用这两个类备份和还原数据库。它由两种形式组成:用于登录应用程序的表单和应用程序主表单。要登录,需要用户输入服务器,用户名和密码,然后使用MySqlBackUp “ValidateConnection功能。如果用户通过验证,则将打开主表单。用户可以选择一个复选框,该复选框将告诉应用程序下次启动该应用程序时要记住它们。这会将当前服务器名称和用户的用户名存储在“应用程序设置”文件中(用户在重新启动时仍必须提供密码)。主要形式由一个组合框组成,该组合框已加载有数据库,用户在数据库上具有足够的权限来创建备份。它具有一个带有两个选项卡的选项卡控件:一个用于备份,另一个用于还原通过组合框选择的数据库。要进行备份,用户只需选择带有组合框的数据库,在提供的文本框中输入文件名,然后按标记为备份”。。要还原数据库,用户只需使用组合框选择数据库,然后使用“ 浏览”按钮选择相关的备份文件,如果文件经过验证,请按“还原”以还原数据库。在两种情况下,都会显示一个进度条,以使用户知道事件的进度。操作完成后,将打开一个消息框,通知用户。如果发生错误,则将告知用户该问题的潜在原因,并提供有关下一步操作的建议。

主窗体加载

在这种情况Load下,我们只是使用MySqlBackUpclass GetDataBases方法检索服务器上数据库的名称,该方法返回List(of String),并将设置为ComboBox.DataSource返回的名称列表。这样可以确保用户选择的数据库确实存在,并且用户能够提取备份。

错误处理

在这一点上至关重要的是,规划出我在备份类中使用的错误处理策略。在整个类中,Using除非我需要捕获一个非常特定的错误(即使是,我只是将错误抛出)以连接到数据库并写入文件,否则我只使用了伪指令。这确保了遇到的任何错误都将返回给调用函数,同时仍确保我的数据库连接等以正确的方式关闭和处理。这意味着所有潜在的错误都需要在UI级别进行处理。这意味着使用TryCatchEnd Try块来调用我们类中的任何方法,然后通过通知用户正在发生的事情并建议他们可以尝试再次尝试来处理错误。这需要研究要调用的方法并找出可能发生的错误,然后处理每个潜在的错误。在我看来,除非您先处理了所有其他潜在的异常,否则处理一般异常并不是一个好习惯。

备份

当用户按下“备份”按钮时,我们首先检查以确保他们输入了文件的有效名称。如果是这样,我们将禁用“备份”和“退出”按钮,并显示进度条(将其设置为0)。然后,我们打开一个,FolderBrowserDialog以便用户可以选择要将备份文件保存到的文件夹,然后将结果与用户输入的文件名一起使用以获取完整的路径字符串(我的备份文件使用.msb扩展名)。然后,我们使用当前用户的用户名,密码,所选数据库和完整路径作为构造函数的参数来实例化新的BackUp类。

Private Sub btnBackUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                       Handles btnBackUp.Click
    If txtFileName.Text = String.Empty Then 
        MsgBox("Please enter valid File Name")
        txtFileName.Focus()
        Exit Sub
    End If
    btnBackUp.Enabled = False 
    btnExit.Enabled = False
    pbBackUp.Visible = True
    pbBackUp.Value = 0
    Try
        Dim fbdBackup As New FolderBrowserDialog 
        fbdBackup.ShowDialog()
        BackUpFileName = fbdBackup.SelectedPath & "/" & txtFileName.Text & ".msb" 
        CurrentBackUp = New BackUp(CurrentServer, _
                    CurrentUser.Name, _
                                   CurrentUser.Password,_
                                   cboDataBaseSelection.SelectedItem.ToString, _
                                   BackUpFileName)
        bgwBackUp.RunWorkerAsync() 
    Catch exMysql As MySqlException 
       MsgBox("There was an error connecting with the server.etc")
    Catch exXML As Xml.XmlException 
        MsgBox("Could not save BackUp File to Disk. Please try again.etc")
    End Try
End Sub

BackGroundWorker在设计时创建了两个,每个处理一个。这是可选的,但建议这样做,因此在创建BackUp类后,我将调用我Backup BackGroundWorkerRunWorkerAsync方法。该Backup BackGroundWorkerDoWork事件是我们拨打电话给我们的BackUp类的BackUpDataBase常规,通过对当前工人作为参数,所以我们可以接受的进度报告。在Backup BackGroundWorkerProgressChanged情况下,我们只设置备份进度条的值到工人的进度百分比。当工作人员完成备份或发生错误时,它将引发其RunWorkerCompleted事件,在该事件中,我们需要分析错误并向用户提供有用的信息,或者让用户知道一切都成功了,然后重置用户界面。

恢复中

在“还原”选项卡上,“还原”按钮被禁用,直到用户选择了有效的备份文件。

选择备份文件

单击浏览按钮后,将向用户显示一个OpenFileDialog以选择备份文件。用户选择文件后,将立即使用我们的“ MySqlBackUp类” ValidateBackUpFile方法对其进行检查。

此方法创建一个新XmlDocument类,并使用该类的Load方法加载所选文档。我们可以调用一个方法GetSchema,该方法可以动态创建一个XML模式。如前所述,XML文件的实际模式非常简单,因此创建其模式也是如此:

Private Function GetSchema() As XmlSchema 
    'Creates basic xml schema to validate selected file 
    Dim BackUpSchema As New Xml.Schema.XmlSchema
    Dim DatabaseElement As New XmlSchemaElement 
    BackUpSchema.Items.Add(DatabaseElement)
    DatabaseElement.Name = "DataBase"
    Dim ctDataBase As New XmlSchemaComplexType()
    DatabaseElement.SchemaType = ctDataBase
    Dim sqDataBase As New XmlSchemaSequence 
    ctDataBase.Particle = sqDataBase 
    Dim eDataBaseName As New XmlSchemaAttribute()
    ctDataBase.Attributes.Add(eDataBaseName)
    eDataBaseName.Name = "Name" 
    eDataBaseName.Use = XmlSchemaUse.Required 
    'Set the DataType for the attribute
    eDataBaseName.SchemaTypeName = _
                 New XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema") 
    Dim xseTables As New XmlSchemaElement()
    sqDataBase.Items.Add(xseTables)
    xseTables.Name = "Tables"
    Dim eConstraints As New XmlSchemaElement()
    sqDataBase.Items.Add(eConstraints)
    eConstraints.Name = "Constraints"
    Dim eInserts As New XmlSchemaElement()
    sqDataBase.Items.Add(eInserts)
    eInserts.Name = "Inserts"
    Dim eViews As New XmlSchemaElement()
    sqDataBase.Items.Add(eViews)
    eViews.Name = "Views"
    Dim eProcedures As New XmlSchemaElement()
    sqDataBase.Items.Add(eProcedures)
    eProcedures.Name = "Procedures"
    Dim eFunctions As New XmlSchemaElement()
    sqDataBase.Items.Add(eFunctions)
    eFunctions.Name = "Functions"
    Dim eEvents As New XmlSchemaElement()
    sqDataBase.Items.Add(eEvents)
    eEvents.Name = "Events"
    Dim eTriggers As New XmlSchemaElement()
    sqDataBase.Items.Add(eTriggers)
    eTriggers.Name = "Triggers"
    Return BackUpSchema
End Function

可以看出,这很容易解释。我们只是将根元素数据库创建为一种ComplexElement类型,创建新的XML序列,并将数据库元素设置为序列的基础。然后,我们向数据库元素添加一个属性,以包含已备份的数据库的名称。然后,只需为其他节点创建简单元素即可。

然后,我们将此架构添加到XmlDocument的架构集合中,然后使用它来验证所选文件。为了处理遇到的任何架构错误,我们需要使用其委托声明一个验证事件处理程序。该处理程序仅引发错误,并期望将其捕获在主UI中。

所选备份文件通过验证后,我们将设置一个标签以显示所选文件并启用“还原”按钮。如果遇到任何错误,我们将用一个Try块将其捕获,按类型捕获潜在的错误并进行适当处理。

恢复中

验证备份文件后,将启用“还原”按钮。当用户单击按钮时,我们首先检查(以防万一)该文件是否有效(记住保存文件名的标签仅具有有效的文件名)。我们还确保用户绝不会误点击。如果确定,那么我们将Restore使用当前用户的详细信息,选定的数据库和选定的文件实例化一个新类。然后,检查文件数据库以确保它与所选数据库相对应,禁用“还原”和“退出”按钮,并显示还原进度栏。然后,我们调用还原来BackGroundworker执行其操作,并在其例程中调用新Restore类的RestoreDatabase方法DoWork。我们使用还原工作者的ProgressChanged例程,当它完成或出现错误时,我们将在RunWorkerCompleted常规。我们终于得到它了。恢复完成==微笑的客户端。

思考要点

我几乎可以在每个可以使用的数据库上抛出该类,到目前为止,它似乎可以处理我设法抛出的所有问题。好吧,让我这样说,在测试期间消除了由测试产生的错误,因此对表的每一列进行了数据类型分析等等。这绝不是我想要的防弹类,因为我尚未在大型数据库上对其进行测试。我认为,即使我有一个要测试,它也不会真正经受住考验。考虑到这一点,我尝试使用的最大数据库最终得到了456 MB的XML文件,创建该文件需要2分钟,而恢复则需要5分钟。试图在记事本中打开文件几乎冻结了我的计算机。我的客户的数据库永远都不会接近这个大小,因此在此阶段无需考虑超出此范围的问题。INSERTs,我可能会将每个插入文件限制为不超过50,000条记录。然后,我将使用主XML文件作为指导,将哪些文件放到哪里,也许只是使用它来按顺序列出生成的文件。

相关推荐

咨询软件
 
QQ在线咨询
售前咨询热线
QQ1922638