C# Winform 实现Oracle 数据库备份软件
Oracle数据库备份软件,实现定时自动备份,并且可以将备份文件以邮件附件的形式发送到指定邮箱。
正常手动备份数据库的时候,大多时候是使用命令行进行备份。
导出数据库的命令是:
exp 用户名/密码@数据库实例名 file=本地存放路径 log=本地日志存放路径
导入数据库的命令是:
imp 用户名/密码@数据库实例名 file=本地数据库文件 fromuser=原用户名 touser=当前用户名 log=本地日志存放路径
所以实现自动备份数据库的思路就是定时执行一条导出数据库的cmd命令。
一、软件设计
1、主窗体:分上下两部分,上边是数据库备份配置列表,下边是备份记录列表。
2、设置:设置备份完成后是否发送邮件进行通知,设置是否发送数据库备份到邮箱,设置日志的存放路径。
3、新建备份:配置带备份的数据库信息
4、新建导出:点击确定直接导出数据库到本地,只是单次导出
5、新建导入:点击确定导入数据库,只是单次导入
二、代码实现
1、本程序中的数据库备份配置和设置页面的内容都是保存到json文件中,所以需要对json文件进行操作:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace BackUp.Winform.Class
{
public static class Json
{
/// <summary>
/// 保存设置
/// </summary>
/// <param name="model"></param>
public static void SaveSetting(Models.Setting model)
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
SaveJson("Setting", json);
}
/// <summary>
/// 保存记录
/// </summary>
/// <param name="model"></param>
public static void SaveRecord(Models.Record model)
{
var lstModel = GetRecord();
lstModel.Add(model);
string json = Newtonsoft.Json.JsonConvert.SerializeObject(lstModel);
SaveJson("Record", json);
}
/// <summary>
/// 删除记录
/// </summary>
/// <param name="database"></param>
/// <param name="username"></param>
/// <param name="starttime"></param>
/// <param name="endtime"></param>
public static void DelRecord(string database, string username, DateTime starttime, DateTime endtime)
{
var lstModel = GetRecord();
int index = lstModel.FindIndex(x => x.DataBase == database && x.Username == username && x.StartTime.ToString("yyyyMMddHHmmss") == starttime.ToString("yyyyMMddHHmmss") && x.EndTime.ToString("yyyyMMddHHmmss") == endtime.ToString("yyyyMMddHHmmss"));
if (index > -1)
{
lstModel.RemoveAt(index);
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(lstModel);
SaveJson("Record", json);
}
/// <summary>
/// 保存备份配置
/// </summary>
/// <param name="model"></param>
public static void SaveBackUp(Models.BackUp model)
{
var lstModel = GetBackUp();
lstModel.Add(model);
string json = Newtonsoft.Json.JsonConvert.SerializeObject(lstModel);
SaveJson("BackUp", json);
}
/// <summary>
/// 修改备份配置
/// </summary>
/// <param name="model"></param>
public static void EditBackUp(Models.BackUp model)
{
var lstModel = GetBackUp();
int index = lstModel.FindIndex(x => x.UuId == model.UuId);
lstModel.RemoveAt(index);
lstModel.Add(model);
string json = Newtonsoft.Json.JsonConvert.SerializeObject(lstModel);
SaveJson("BackUp", json);
}
/// <summary>
/// 删除备份配置
/// </summary>
/// <param name="uuId"></param>
public static void DelBackUp(string uuId)
{
var lstModel = GetBackUp();
int index = lstModel.FindIndex(x => x.UuId == uuId);
if (index > -1)
{
lstModel.RemoveAt(index);
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(lstModel);
SaveJson("BackUp", json);
}
/// <summary>
/// 获取设置
/// </summary>
/// <returns></returns>
public static Models.Setting GetSetting()
{
string json = GetJson("Setting");
return string.IsNullOrEmpty(json)
? new Models.Setting() : Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Setting>(json);
}
/// <summary>
/// 获取记录
/// </summary>
/// <returns></returns>
public static List<Models.Record> GetRecord()
{
string json = GetJson("Record");
return string.IsNullOrEmpty(json)
? new List<Models.Record>() : Newtonsoft.Json.JsonConvert.DeserializeObject<List<Models.Record>>(json).OrderByDescending(p=>p.EndTime).ToList();
}
/// <summary>
/// 获取备份配置
/// </summary>
/// <returns></returns>
public static List<Models.BackUp> GetBackUp()
{
string json = GetJson("BackUp");
return string.IsNullOrEmpty(json)
? new List<Models.BackUp>() : Newtonsoft.Json.JsonConvert.DeserializeObject<List<Models.BackUp>>(json).OrderByDescending(p => p.PostTime).ToList();
}
/// <summary>
/// 保存JSON数据
/// </summary>
/// <param name="filename"></param>
/// <param name="json"></param>
private static void SaveJson(string filename, string json)
{
try
{
string exeFolder = System.Windows.Forms.Application.StartupPath + "\\";
string Directory = exeFolder + "Json\\";
string filepath = Directory + "\\" + filename + ".json";
if (!System.IO.Directory.Exists(Directory))
System.IO.Directory.CreateDirectory(Directory);
File.WriteAllText(filepath, json);
}
catch (Exception e)
{
WriteTxt("保存JSON", $"{filename}.json 保存出错:\r\n{e.Message}");
}
}
/// <summary>
/// 获取JSON数据
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
private static string GetJson(string filename)
{
string res = "";
try
{
string exeFolder = System.Windows.Forms.Application.StartupPath + "\\";
string Directory = exeFolder + "Json\\";
string filepath = Directory + "\\" + filename + ".json";
// 创建一个 StreamReader 的实例来读取文件
// using 语句也能关闭 StreamReader
using (StreamReader sr = new StreamReader(filepath))
{
string line;
// 从文件读取并显示行,直到文件的末尾
while ((line = sr.ReadLine()) != null)
{
res += line;
}
}
}
catch (Exception e)
{
WriteTxt("获取JSON", $"{filename}.json 读取出错:\r\n{e.Message}");
}
return res;
}
/// <summary>
/// 记录日志
/// </summary>
/// <param name="folder">该日志所在文件夹名字</param>
public static void WriteTxt(string folder, string content)
{
try
{
string exeFolder = System.Windows.Forms.Application.StartupPath + "\\";
string Directory = exeFolder + "logs\\" + folder;
string filepath = Directory + "\\日志(" + DateTime.Now.ToString("yyyy-MM-dd") + ").txt";
if (!System.IO.Directory.Exists(Directory))
System.IO.Directory.CreateDirectory(Directory);
StreamWriter sw = new StreamWriter(filepath, true, Encoding.UTF8);
sw.WriteLine("[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "]:");
sw.WriteLine("***************************分隔符【开始】***********************************");
sw.WriteLine(content);
sw.WriteLine("***************************分隔符【结束】***********************************\r\n");
sw.Close();
}
catch { }
}
}
}
2、实现自动备份和导出导入的思路是执行cmd命令,所以需要对cmd命令进行操作:
/// <summary>
/// 执行cmd命令
/// </summary>
public void RunCmd()
{
lock (_cmd)
{
try
{
//string strInput = Console.ReadLine();
Process p = new Process();
//设置要启动的应用程序
p.StartInfo.FileName = "cmd.exe";
//是否使用操作系统shell启动
p.StartInfo.UseShellExecute = false;
// 接受来自调用程序的输入信息
p.StartInfo.RedirectStandardInput = true;
//输出信息
p.StartInfo.RedirectStandardOutput = true;
// 输出错误
p.StartInfo.RedirectStandardError = true;
//不显示程序窗口
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
//启用Exited事件
p.EnableRaisingEvents = true;
p.Exited += new EventHandler(Process_Exited);
//启动程序
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.StandardInput.AutoFlush = true;
//输入命令
_startTime = DateTime.Now;
p.StandardInput.WriteLine(_cmd);
p.StandardInput.WriteLine("exit");
}
catch (Exception ex)
{
Class.Json.WriteTxt("CMD", $"执行cmd命令出错:\r\ncmd:{_cmd}\r\n{ex.Message}");
}
}
}
private void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
SetLogContent(e.Data);
}
}
private void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
SetLogContent(e.Data);
}
}
private void Process_Exited(object sender, EventArgs e)
{
//备份的时候要更新配置中的下次执行时间
if (_backUp.Type == Models.BackType.备份)
{
_backUp.LastExecuteTime = _startTime;
_backUp.NextExecuteTime = GetNextExecuteTime(_startTime, _backUp.Times);
Class.Json.EditBackUp(_backUp);
}
SetLogContent("命令执行完毕");
WriteTxt(_logFolder);
_isok = _logsContent.Contains("成功")&& !_logsContent.Contains("未成功");
_isloading = false;
_endTime = DateTime.Now;
SaveRecord();
}
3、导入和导出只需要将填写到textbox中的内容拼接成一句导出或导入的cmd命令,然后扔到这个方法里执行就可以了。重点是如何自动备份数据库,也就是如何定时自动执行一条导出的cmd命令。
其实只需要用到timer控件。
在主窗体中拖入timer控件
设置四秒钟执行一次
然后在主窗体的构造函数中启动该timer
public Fm_Main()
{
InitializeComponent();
fm_Loading = new Fm_Loading();
timer.Start();
timerBackUp.Start();//启动备份定时器
}
写一个自动备份的方法,供timerBackUp调用
/// <summary>
/// 自动备份
/// </summary>
private void BackUpAuto()
{
lock (BackUp.Username)
{
if (IsExceing) return;
if (BackUp == null) return;
string now = DateTime.Now.ToString("yyyyMMddHHms");
string cmd = $"exp {BackUp.Username}/{BackUp.Password}@{BackUp.DataBase} file={BackUp.Path}\\Backup_{BackUp.Username}_{now}.dmp";
if (BackUp.IsLogs)
{
cmd += $" log={BackUp.LogPath}\\Backup_{BackUp.Username}_{now}.log";
}
ThreadRun(cmd, $"{BackUp.Path}\\Backup_{BackUp.Username}_{now}.dmp", BackUp, "自动备份");
}
}
这里启动另一个线程去执行cmd命令
/// <summary>
/// 线程里运行
/// </summary>
/// <param name="cmd"></param>
/// <param name="filePath"></param>
/// <param name="backUp"></param>
/// <param name="logsfolder"></param>
private void ThreadRun(string cmd, string filePath, Models.BackUp backUp, string logsfolder)
{
FilePath = filePath;
Cmd = cmd;
LogsFolder = logsfolder;
BackUp = backUp;
bool isSuccess = false;
fm_Loading = new Fm_Loading();
IsExceing = true;
tsslStatus.Text = $@"状态:正在{logsfolder}...";
tsslStatus.ForeColor = Color.Black;
fm_Loading = new Fm_Loading();
Thread th = new Thread(new ThreadStart(RunCmd));//这里调用的就是前边定义的执行cmd命令的方法
th.Start();
IsExceing = false;
isSuccess = fm_Loading.ShowDialog() == DialogResult.OK;
tsslStatus.Text = isSuccess ? $@"状态:{logsfolder}成功" : $@"状态:{logsfolder}失败";
tsslStatus.ForeColor = isSuccess ? Color.Green : Color.Red;
if (isSuccess && BackUp.Type != Models.BackType.导入)
{
SendMail($"Oracle数据库{logsfolder}:{BackUp.Username}",
Newtonsoft.Json.JsonConvert.SerializeObject(BackUp), FilePath);
}
}
在timer的tick事件中写如下代码,实现定时备份:
private void timerBackUp_Tick(object sender, EventArgs e)
{
DateTime thisTime = DateTime.Now;
//判断备份配置列表中下一次执行时间是否在当前时间的前两秒和后两秒内
var backUp = BackUps.Find(x =>
x.NextExecuteTime < thisTime.AddSeconds(2) && x.NextExecuteTime > thisTime.AddSeconds(-2));
if (backUp != null && backUp.IsUse)
{
if (IsExceing) return;
BackUp = backUp;
BackUpAuto();
LoadBackUpList();
}
}
以上就是实现一个自动备份Oracle数据库程序的思路了,具体的代码我放到了以下两个地方:
CSDN:有现成的软件和源码,下载需要积分:
软件:https://download.csdn.net/download/weixin_42281203/13204541
源码:https://download.csdn.net/download/weixin_42281203/13204560
Gitee:只有源码,下载地址:https://gitee.com/blackvon/oracle-back-up
欢迎访问作者个人技术博客:BlackvonCode(www.blackvon.cn)