西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页西西教程数据库教程 → 用C# 制作MySQL数据库批量备份还原工具

用C# 制作MySQL数据库批量备份还原工具

相关软件相关文章发表评论 来源:西西整理时间:2011/12/10 16:09:18字体大小:A-A+

作者:西西点击:333次评论:0次标签: MySQL

  • 类型:电子教程大小:8.5M语言:中文 评分:8.3
  • 标签:
立即下载

   在这篇文章我们学习用C#来操作,并制作一个备份还原工具。

  我们要操作cmd.exe使用到了Process类,使用这个类首先要引入命名空间  System.Diagnostics,此类提供对本地和远程进程的访问并能够启动和停止本地系统进程。

        /// <summary>
        /// 执行Cmd命令
        /// </summary>
        /// <param name="workingDirectory">要启动的进程的目录</param>
        /// <param name="command">要执行的命令</param>
        public static void StartCmd(String workingDirectory, String command)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.WorkingDirectory = workingDirectory;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;

            p.Start();
            p.StandardInput.WriteLine(command);
            p.StandardInput.WriteLine("exit");
            p.WaitForExit();
            p.Close();

        }

在看看如何使用上方法:

string appDircectroy="C:\\Program Files\\MySQL\\MySQL Server 5.5\\bin"
string cmd="mysqldump -hlocalhost  -uroot -proot --default-character-set=utf8 --lock-tables --routines --force  --quick Dbname>d:\backup.sql"

  StartCmd(appDircectroy,cmd);

这里我们同Process操作cmd.exe,调用mysqldump.exe 执行命令"-hlocalhost  -uroot -proot --default-character-set=utf8 --lock-tables --routines --force  --quick Dbname>d:\backup.sql"备份数据库。其实我们也可以直接通过Process类直接调用mysqldump.exe进程执行命令,写法如下:

        /// <summary>
        /// 使用mysqldump执行command命令
        /// </summary>
        /// <param name="AppPath">mysqldump.exe的目录</param>
        /// <param name="command"></param>
       public static void StartMySqldump(string AppPath, string command)
        {
            ProcessStartInfo psi = new ProcessStartInfo(AppPath + @"\mysqldump.exe");
            psi.Arguments = command;
            psi.UseShellExecute = false; psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;
            psi.CreateNoWindow = true;
            Process pro = Process.Start(psi);
            pro.WaitForExit();
            pro.Close();
        }

 调用的方法和上面的使用基本一致,就是command命令不需要写mysqldump 改为"-hlocalhost  -uroot -proot --default-character-set=utf8 --lock-tables --routines --force  --quick Dbname>d:\backup.sql" 。

    我再这里使用方法1,比较灵活方便,因为我们原因的使用也可以用到此方法执行mysql.exe还原命令,上篇中说到还原时,数据库如何不存在的使用,我们要先创建数据库,再还原,那么就是要执行两天命令,我们可以改一下方法1,使它可以执行多条命令,如下:

        /// <summary>
        /// 执行Cmd命令
        /// </summary>
        /// <param name="workingDirectory">要启动的进程的目录</param>
        /// <param name="command">要执行的命令</param>
        public static void StartCmd(String workingDirectory, String[] commands)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.WorkingDirectory = workingDirectory;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            foreach (string cmd in commands)
            {
                p.StandardInput.WriteLine(cmd);
              
            }
            p.StandardInput.WriteLine("exit");
            p.WaitForExit();
            p.Close();

        }

      有了上面的函数,编写一个winform备份还原工具就比较容易实现了,但是现在我要备份300多个数据库,我要生成300多个数据库备份文件,当然我们也可以通过命令将300多个数据库,即所有数据库(包含mysql自带的系统库)备份到一个文件夹。还有一点要注意就是用户体验,假如备份的一个数据库很大,那么直接调用就会吧UI卡死,所以我们要用异步线程来解决此问题,我打算用四个线程同时执行备份,直到300多个数据库执行完毕。

   有人可能对线程不熟悉,不用怕,其实.net提供了一个异步线程的封装 BackgroundWorker,用此类可以很简单实现。  我们用到BackgroundWorker提供的两个事件DoWork和RunWorkerCompleted,DoWork中写线程开始要执行的任务,RunWorkerCompleted中写线程执行的任务结束要执行的工作。看看简单的代码示例:

BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
 backgroundWorker.RunWorkerAsync(remainDbNames); //remainDbName是list<string>类型, 传入的参数,我保存要备份的库的名字,备份一个库就移除一个库

 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)  {             List<string> names = e.Argument as List<string>; //获取传入的参数ramainDbName

            BackupMany(filePath, names, boolBackdata); //执行备份方法             //e.Result = e.Argument.ToString();   //完成任务时向RunWorkerCompleted方法传递的结果参数

  }

   private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)    {

            // writeText(textResult,true,"完成数据库"+e.Result.ToString()+"备份操作" + Environment.NewLine);

  }

使用就是那么简单,下面看看我启用四个线程同时备份:

              //只有在备份按钮事件中生成个异步线程即可
                for (int i = 0; i < 4; i++)
                {
                    BackgroundWorker backgroundWorker = new BackgroundWorker();
                    backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
                    backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
                    backgroundWorker.RunWorkerAsync(remainDbNames);
                }

下面看看单个线程具体如何从remainDbName中取数据库的名字执行备份

    object lockobject = new object(); //备份时的lock对象
    delegate void WriteText(TextBox textbox, bool append, string text);
        private void writeText(TextBox textbox, bool append, string msg)
        {
            if (this.InvokeRequired)
            {
                WriteText d = new WriteText(writeText);
                object[] obj = new object[3];
                obj[0] = textbox;
                obj[1] = append;
                obj[2] = msg;
                this.Invoke(d, obj);
            }
            else
            {
                if (append)
                    textbox.AppendText(msg);
                else
                    textbox.Text = msg;
            }
        }
        private void BackupMany(string path, List<string> dbNames, bool backupdata)
        {
            string name = null;
            lock (lockobject)
            {
                if (dbNames.Count > 0)
                {
                    name = dbNames[0];
                    dbNames.RemoveAt(0);
                }
            }
            if (name != null)
            {
                Backup(path, name, backupdata);
                BackupMany(path, dbNames, backupdata);
            }
            else
            {
                timer1.Enabled = false;
                writeText(textResult, true, "全部执行完成!");
            }

        }

        private void Backup(string path, string databaseName, bool backupdata)
        {
            try
            {
                writeText(textResult, true, DateTime.Now.ToString() + " 开始数据库" + databaseName + "备份" + Environment.NewLine);
                //String command = "mysqldump --quick --host=localhost --default-character-set=gb2312 --lock-tables --verbose  --force --port=端口号 --user=用户名 --password=密码 数据库名 -r 备份到的地址";
                //构建执行的命令
                String directory = path + "\\" + databaseName + ".sql";
                String command;
                if (backupdata)
                {
                    command = string.Format("mysqldump --quick --host={1} --default-character-set={2}  --lock-tables --routines --force --port={3} --user={4} --password={5} {6} -r \"{0}\"",
                            directory, host, characterSet, port, user, password, databaseName);
                }
                else
                {
                    command = string.Format("mysqldump --quick --host={1} --default-character-set={2} -d --lock-tables  --routines --force --port={3} --user={4} --password={5} {6} -r \"{0}\"",
                         directory, host, characterSet, port, user, password, databaseName);
                }
                Cmd.StartCmd(appDirecroty, command);
                writeText(textResult, true, DateTime.Now.ToString() + @" 数据库已成功备份到 " + directory + " 文件中" + Environment.NewLine);
                counter++;
                writeText(textBox1, false, "共" + totlecount + "个文件,已完成" + counter + "个文件");
            }
            catch (Exception ex)
            {
                writeText(txtErr, true, DateTime.Now.ToString() + " 数据库" + databaseName + "备份失败!");
            }
        }


writeText是向TextBox写入文本的方法,因为副线程操作主线程生成的控件时,会有线程安全问题,所以要用异步委托。如何你知道这个怎么用,其实还有一个简单点的方法,就是把前程安全检查给关闭掉,在窗体onload中可以加入Control.CheckForIllegalCrossThreadCalls = false; 这句就可以跨线程操作UI而不会报错。
    还原的实现和备份的操作差不多,这里就不提了。本想上传个一下代码可是找不到上传的方法。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)