///还原资料文件夹 ///经过主窗体的逻辑,可以认为,传过来的快照对象实例包含所有的需要还原的文件 ///而且,快照记录的所有文件在文件夹中都一一对应 ///不方便改名,这个方法其实是所有拷贝文件的方法,将第二个参数里所有内容拷贝到第三个参数的文件夹中,二/三参数在拷贝完后是平级的. public static void RestoredFiles(List <string> fileGhost, string backupFilesPath, string restoredFilesPath, SkinListBox listbox) { listbox.AddToButtom("开始拷贝文件..."); WaitThreadControl wtc = new WaitThreadControl { RecordedDatabase = false }; Thread thread = new Thread((q) => { //todo:拷贝文件的逻辑,需要考虑如果目标磁盘满了,或者其他错误导致的还原中断,如何处理. //可以使用try块来捕获异常 //调用递归,参数为两个路径,表示为将第一个路径所代表的文件夹拷贝到第二个路径下面 //路径格式为第一个参数为快照中每一个文件夹名字完整路径,第二个参数,为目标文件夹完整路径 foreach (var item in fileGhost) { CopyDirectory(backupFilesPath + "\\" + item, restoredFilesPath);//todo:将等待窗体放进参数里,在每次拷贝一个文件后,改变等待窗体显示的内容,用invoke } ((WaitThreadControl)q).RecordedDatabase = true; listbox.Invoke(new Action <string>(n => listbox.AddToButtom(n)), "拷贝完成...OK"); }); thread.IsBackground = true; thread.Start(wtc);//要先执行线程再谈对话框,不然会阻塞. WaitDialog wd = new WaitDialog(wtc); wd.StartPosition = FormStartPosition.CenterParent; wd.chengeLoadingText("正在拷贝数据文件"); wd.ShowDialog(); }
/// <summary> /// 备份指定的数据库文件 /// </summary> /// <param name="databasefile">备份文件要存放到的路径</param> /// <returns></returns> public static bool BackUpDataBase(string databasefile, UserInfo userinfo, SkinListBox listbox, bool isFullBackup) { ///调用时,由调用函数先确认是否存在完整备份的文件,有则先进行处理,确保执行备份时,文件已被删除或改名. ///这里的逻辑,不再校验是否有备份文件. ///只做单一的完整备份或差异备份 ///RESTORE DATABASE [dzcjda_sjz] FROM DISK = N'H:\xuz\dif_20170516.bak' WITH FILE = 1, MOVE N'dzcjda_sjz' TO N'F:\sql2008shili\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\dzcjda_sjz.mdf', MOVE N'dzcjda_sjz_log' TO N'F:\sql2008shili\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\dzcjda_sjz_1.ldf', NOUNLOAD, STATS = 10 ///if (File.Exists(databasefile)) ///{ /// return false; ///} WaitThreadControl wtc = new WaitThreadControl { RecordedDatabase = false }; Thread thread = new Thread((q) => { //还原的数据库MyDataBase string sql; if (isFullBackup) { //sql = "BACKUP DATABASE @baseName TO DISK = @backFilePath "; sql = "BACKUP DATABASE @baseName TO DISK = @backFilePath WITH NOFORMAT, INIT, NAME = N'dzcjda_sjz-完整 数据库 备份', SKIP, NOREWIND, NOUNLOAD, STATS = 10"; } else { sql = "BACKUP DATABASE @baseName TO DISK = @backFilePath WITH DIFFERENTIAL , NOFORMAT, INIT, NAME = N'dzcjda_sjz-差异 数据库 备份', SKIP, NOREWIND, NOUNLOAD, STATS = 10"; } //string sql1 = @"BACKUP DATABASE [MZLWebApp] TO DISK = '" + databasefile + ".bak' WITH NOFORMAT, NOINIT, NAME = '"+ DateTime.Now.ToString("yyyyMMdd") +"', SKIP, NOREWIND, NOUNLOAD, STATS = 10"; SqlParameter[] spms = new SqlParameter[] { new SqlParameter("@baseName", userinfo.BaseName), new SqlParameter("@backFilePath", databasefile) }; try { SQLHelper.ExecutNonQuery(sql, CommandType.Text, spms); } catch (Exception) { listbox.Invoke(new Action <string>(n => listbox.AddToButtom(n)), "备份失败...False"); ((WaitThreadControl)q).RecordedDatabase = true; return; } listbox.Invoke(new Action <string>(n => listbox.AddToButtom(n)), "备份成功...OK"); ((WaitThreadControl)q).RecordedDatabase = true; }); thread.IsBackground = true; WaitDialog wd = new WaitDialog(wtc); wd.chengeLoadingText("正在备份数据库"); wd.StartPosition = FormStartPosition.CenterParent; thread.Start(wtc);//要先执行线程再谈对话框,不然会阻塞. wd.ShowDialog(); return(true); }
//以下是一键还原数据库(通过最后一个参数指定是完整还原还是差异还原,完整还原,第一个参数只要一个文件名,差异还原则要两个)------------------------------------ /// <summary> /// 一键还原数据库 /// </summary> /// <param name="backfile">一个或两个文件,完全备份和差异备份</param> /// <param name="userinfo"></param> /// <param name="listbox"></param> /// <param name="type">是完整还原还是差异还原</param> /// <returns></returns> public static bool FullRestoreDatabase(string[] backfile, UserInfo userinfo, SkinListBox listbox, BacOrResType type) { ///杀死原来所有的数据库连接进程 ArrayList list = new ArrayList(); string sql = "SELECT spid FROM sysprocesses ,sysdatabases WHERE sysprocesses.dbid=sysdatabases.dbid AND sysdatabases.Name=@baseName"; SqlParameter spm = new SqlParameter("@baseName", userinfo.BaseName); using (SqlDataReader reader = SQLHelper.ExcuteDataReader(sql, CommandType.Text, spm)) { if (reader.HasRows) { while (reader.Read()) { list.Add(reader.GetInt16(0)); } } } for (int i = 0; i < list.Count; i++) { sql = string.Format("KILL {0}", list[i].ToString()); SQLHelper.ExecutNonQuery(sql, CommandType.Text, null); //MessageBox.Show("系统已经清除的数据库线程: " + list[i].ToString() + "\r\n正在还原数据库!"); listbox.AddToButtom("清除数据库线程: " + list[i].ToString()); } listbox.AddToButtom("所有线程清理完成...OK"); //listbox.AddToButtom("开始执行完整还原操作..."); listbox.AddToButtom(type == BacOrResType.Full ? "开始完整还原数据库..." : "开始差异还原数据库..."); WaitThreadControl wtc = new WaitThreadControl { RecordedDatabase = false }; #region 通过斜线旋转执行等待 //Thread waitThread = new Thread((canStop) => // { // string[] strArray = new string[] { "/", "—", "\\" }; // int i = 0; // WaitDialog wd = new WaitDialog(); // wd.StartPosition = FormStartPosition.CenterParent; // listbox.Invoke(new Action<WaitDialog>(wd1 => // { // ((WaitDialog)wd1).ShowDialog(); // }), wd); // while (!((WaitThreadControl)canStop).RecordedDatabase) // { // int b; // Math.DivRem(i, 3, out b); // listbox.Invoke(new Action(() => // { // listbox.Items.RemoveAt(listbox.Items.Count - 1); // listbox.AddToButtom("正在还原数据库,禁止所有操作..." + strArray[b]); // })); // i++; // Thread.Sleep(300); // } // listbox.Invoke(new Action<string>(u => // { // listbox.Items.RemoveAt(listbox.Items.Count - 1); // listbox.AddToButtom(u); // }), "还原数据库执行完成...OK"); // }); #endregion Thread thread = new Thread((q) => { bool hasBase = ConnectionTestInfo.CheckExistsDataBase(userinfo); //数据库已经存在时,不需要加move关键字,但需要覆盖. //数据库不存在时,需要加move,但不需要覆盖 string movPath = hasBase ? "" : @"MOVE @mdfFileName TO @mdfFilePath , MOVE @logFileName TO @logFilePath ,";//数据库是否存在 string defaultPath = string.Empty; if (!hasBase) { #region 获取数据库默认路径代码 listbox.Invoke(new Action <string>(n => { listbox.AddToButtom(n); }), "获取系统默认路径...");//.AddToButtom("获取系统默认路径..."); sql = "select filename from master..sysfiles"; using (SqlDataReader reader = SQLHelper.ExcuteDataReader(sql, CommandType.Text)) { if (reader.HasRows) { if (reader.Read()) { defaultPath = Path.GetDirectoryName(reader.GetString(0)); } } } if (string.IsNullOrEmpty(defaultPath)) { listbox.Invoke(new Action <string>(n => { listbox.AddToButtom(n); }), "获取系统默认路径失败,需指定数据库存放路径..."); //listbox.AddToButtom("获取系统默认路径失败,需指定数据库存放路径"); //todo:弹出对话框 } else { listbox.Invoke(new Action <string, string>((n, m) => { listbox.AddToButtom(n); listbox.AddToButtom(m); }), "获取默认路径成功...OK", defaultPath); //listbox.AddToButtom("获取默认路径成功"); //listbox.Invoke(new Action<string>(n => { listbox.AddToButtom(n); }), defaultPath); //listbox.AddToButtom(defaultPath); } #endregion } if (type == BacOrResType.Full) { sql = @"RESTORE DATABASE @baseName FROM DISK = @backFileName WITH FILE = 1, " + movPath + " NOUNLOAD, REPLACE, STATS = 10";//NORECOVERY, } else { sql = "RESTORE DATABASE @baseName FROM DISK = @backFileName WITH FILE = 1, " + movPath + " NORECOVERY, REPLACE, NOUNLOAD, STATS = 10"; } SqlParameter[] spms = new SqlParameter[] { new SqlParameter("@baseName", userinfo.BaseName), new SqlParameter("@backFileName", backfile[0]), new SqlParameter("@mdfFileName", userinfo.BaseName), new SqlParameter("@mdfFilePath", defaultPath + "\\" + userinfo.BaseName + ".mdf"), new SqlParameter("@logFileName", userinfo.BaseName + "_log"), new SqlParameter("@logFilePath", defaultPath + "\\" + userinfo.BaseName + ".ldf") }; SQLHelper.ExecutNonQuery(sql, CommandType.Text, true, spms); //listbox.Invoke(new Action<string> ( u => listbox.AddToButtom(u) ),"执行完成"); if (type == BacOrResType.Def) { spms[1] = new SqlParameter("@backFileName", backfile[1]); sql = @"RESTORE DATABASE @baseName FROM DISK = @backFileName WITH FILE = 1, NOUNLOAD, STATS = 10"; SQLHelper.ExecutNonQuery(sql, CommandType.Text, true, spms); } ((WaitThreadControl)q).RecordedDatabase = true; listbox.Invoke(new Action <string>(n => listbox.AddToButtom(n)), "还原完成...OK"); }); thread.IsBackground = true; thread.Start(wtc);//要先执行线程再谈对话框,不然会阻塞. WaitDialog wd = new WaitDialog(wtc); wd.chengeLoadingText("正在还原数据库"); wd.StartPosition = FormStartPosition.CenterParent; wd.ShowDialog(); //waitThread.IsBackground = true; //waitThread.Start(wtc); return(true); #region 原来的代码 //这里一定要是master数据库,而不能是要还原的数据库,因为这样便变成了有其它进程 //占用了数据库。 //string constr = userinfo.ConnectionString; //string database = userinfo.BaseName;//MyDataBase; //string path = backfile; //string BACKUP = String.Format("RESTORE DATABASE {0} FROM DISK = '{1}'", database, path); //SqlConnection con = new SqlConnection(constr); //SqlCommand cmd = new SqlCommand(BACKUP, con); //con.Open(); //try //{ // cmd.ExecuteNonQuery(); // MessageBox.Show("还原成功,点击退出系统!"); // Application.Exit(); //} //catch (SqlException ee) //{ // //throw(ee); // //MessageBox.Show("还原失败"); // MessageBox.Show(ee.ToString()); //} //finally //{ // con.Close(); //} //return "成功与否字符串"; #endregion }