[小技术应用]使用windows服务备份数据
1.使用VS2005创建windows服务,从工具箱的组件表当中拖动一个Timer对象到这个设计表面上 (注意: 要确保是从组件列表而不是从Windows窗体列表当中使用Timer) ,修改“.Designer.cs”文件,将timer组件修改为继承自System.Timers.Timer
2.在设计器右键选择添加安装程序,设置serviceInstaller1组件的属性:
1) ServiceName = My Sample Service
2) StartType = Automatic (开机自动运行)
3. 设置serviceProcessInstaller1组件的属性 Account = LocalSystem
4.添加资源文件Config.xml,如下:
<?xml version="1.0" encoding="utf-8" ?>
<Table>
<Row>
<Server>.</Server>
<User>sa</User>
<Pwd>123456</Pwd>
<DataBase>Northwind</DataBase>
<Time></Time>
<Frequency>1</Frequency>
</Row>
</Table>
<Table>
<Row>
<Server>.</Server>
<User>sa</User>
<Pwd>123456</Pwd>
<DataBase>Northwind</DataBase>
<Time></Time>
<Frequency>1</Frequency>
</Row>
</Table>
5.在双击这个Timer,然后在里面写一些数据库操作的代码,下面是Service1.cs全部代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Configuration.Install;
using Microsoft.Win32;
using System.Data.SqlClient;
using System.IO;
namespace DataBaseBakupServer
{
public partial class Service1 : ServiceBase
{
#region 变量
private string Path;
//上次备份日期
private string _time;
//间隔天数
private int _Frequency;
private string _constr;
private string _server;
private string _user;
private string _pwd;
private string _database;
#endregion
public Service1()
{
InitializeComponent();
GetServicePath();
InitData();
}
#region 初始化服务信息
private void InitData()
{
DataSet ds = new DataSet();
ds.ReadXml(Path + "Config.xml");
DataRow dr = ds.Tables[0].Rows[0];
_time = dr["Time"].ToString();
_Frequency = Convert.ToInt32(dr["Frequency"].ToString());
_server = dr["Server"].ToString();
_user = dr["User"].ToString();
_pwd = dr["Pwd"].ToString();
_database = dr["DataBase"].ToString();
_constr = string.Format("server={0};database={1};User Id={2};pwd={3}", _server, "master", _user, _pwd);
}
private void GetServicePath()
{
try
{
RegistryKey rk = Registry.LocalMachine;
RegistryKey rkSub = rk.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\DataBaseBakupServer");
string servicePath = rkSub.GetValue("ImagePath").ToString();
string exePath = servicePath.Substring(servicePath.LastIndexOf("\\") + 1);
string tmp = servicePath.Substring(1, servicePath.Length - exePath.Length-1);
Path = tmp;
}
catch { }
}
#endregion
//必须注意:我明明是从“组件”下添加的“Timer”应该来自“System.Timers命名空间”(“System.Timers.Timer”才能在Windows服务程序中正常定时调用),但是现在Timer却继承至“System.Windows.Forms.Timer”。所以得修改“.Designer.cs”文件
#region 启动和关闭
protected override void OnStart(string[] args)
{
// TODO: 在此处添加代码以启动服务。
timer1.Enabled = true;
timer1.Start();
WriteLog(string.Format("{0} 数据库备份服务启动", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
protected override void OnStop()
{
// TODO: 在此处添加代码以执行停止服务所需的关闭操作。
timer1.Stop();
timer1.Enabled = false;
WriteLog(string.Format("{0} 数据库备份服务关闭", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
#endregion
#region 备份操作
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//定时操作
if (_time == "" || _time == null)
{
//没有保存上次本分时间,可能是第一次执行备份
//WriteLog(string.Format("{0} 开始备份操作", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
Bakup();
InitData();
//WriteLog(string.Format("{0} 备份操作完成", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
return;
}
string now = DateTime.Now.ToString("yyyy-MM-dd");
if (this.DateDiff(Convert.ToDateTime(now), Convert.ToDateTime(_time)) >= _Frequency)
{
//WriteLog(string.Format("{0} 开始备份操作", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
Bakup();
InitData();
//WriteLog(string.Format("{0} 备份操作完成", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
return;
}
}
#endregion
#region 方法
private bool Bakup()
{
string file = DateTime.Now.ToString("yyyyMMddHHmm");
string sql = string.Format("BACKUP DATABASE {1} TO DISK = '{0}.bak'", Path + "Bak\\" + file, _database);
SqlConnection con = new SqlConnection(_constr);
SqlCommand cmd = new SqlCommand(sql, con);
try
{
con.Open();
cmd.ExecuteNonQuery();
WriteBakDate();
return true;
}
catch(Exception e)
{
WriteLog(string.Format("{1} 备份数据库失败!原因可能是{0}", e.Message, DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
return false;
}
finally
{
con.Close();
}
}
/// <summary>
/// 计算2个时间的差值(单位:天)
/// </summary>
/// <param name="DateTime1"></param>
/// <param name="DateTime2"></param>
/// <returns></returns>
private int DateDiff(DateTime DateTime1, DateTime DateTime2)
{
int dateDiff = 0;
try
{
TimeSpan ts1 = new TimeSpan(DateTime1.Ticks);
TimeSpan ts2 = new TimeSpan(DateTime2.Ticks);
TimeSpan ts = ts1.Subtract(ts2).Duration();
dateDiff = ts.Days;
}
catch
{
}
return dateDiff;
}
private void WriteBakDate()
{
try
{
DataSet ds = new DataSet();
ds.ReadXml(Path + "\\Config.xml");
DataRow dr = ds.Tables[0].Rows[0];
dr.BeginEdit();
dr["Time"] = DateTime.Now.ToString("yyyy-MM-dd");
dr.EndEdit();
ds.WriteXml(Path + "Config.xml");
WriteLog(string.Format("{0} 备份数据库成功!", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
catch (Exception e)
{
WriteLog(string.Format("{1} 备份数据库成功!但写入配置文件最后备份时间项失败,原因可能是{0}", e.Message, DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
}
#endregion
#region 日志
private void WriteLog(string s)
{
FileStream fs = new FileStream(Path + "log.txt", FileMode.OpenOrCreate);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
try
{
string tmp = sr.ReadToEnd();
tmp += "\r\n" + s;
sw.Write(tmp);
}
catch
{ }
finally
{
sw.Close();
sr.Close();
fs.Close();
}
}
#endregion
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Configuration.Install;
using Microsoft.Win32;
using System.Data.SqlClient;
using System.IO;
namespace DataBaseBakupServer
{
public partial class Service1 : ServiceBase
{
#region 变量
private string Path;
//上次备份日期
private string _time;
//间隔天数
private int _Frequency;
private string _constr;
private string _server;
private string _user;
private string _pwd;
private string _database;
#endregion
public Service1()
{
InitializeComponent();
GetServicePath();
InitData();
}
#region 初始化服务信息
private void InitData()
{
DataSet ds = new DataSet();
ds.ReadXml(Path + "Config.xml");
DataRow dr = ds.Tables[0].Rows[0];
_time = dr["Time"].ToString();
_Frequency = Convert.ToInt32(dr["Frequency"].ToString());
_server = dr["Server"].ToString();
_user = dr["User"].ToString();
_pwd = dr["Pwd"].ToString();
_database = dr["DataBase"].ToString();
_constr = string.Format("server={0};database={1};User Id={2};pwd={3}", _server, "master", _user, _pwd);
}
private void GetServicePath()
{
try
{
RegistryKey rk = Registry.LocalMachine;
RegistryKey rkSub = rk.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\DataBaseBakupServer");
string servicePath = rkSub.GetValue("ImagePath").ToString();
string exePath = servicePath.Substring(servicePath.LastIndexOf("\\") + 1);
string tmp = servicePath.Substring(1, servicePath.Length - exePath.Length-1);
Path = tmp;
}
catch { }
}
#endregion
//必须注意:我明明是从“组件”下添加的“Timer”应该来自“System.Timers命名空间”(“System.Timers.Timer”才能在Windows服务程序中正常定时调用),但是现在Timer却继承至“System.Windows.Forms.Timer”。所以得修改“.Designer.cs”文件
#region 启动和关闭
protected override void OnStart(string[] args)
{
// TODO: 在此处添加代码以启动服务。
timer1.Enabled = true;
timer1.Start();
WriteLog(string.Format("{0} 数据库备份服务启动", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
protected override void OnStop()
{
// TODO: 在此处添加代码以执行停止服务所需的关闭操作。
timer1.Stop();
timer1.Enabled = false;
WriteLog(string.Format("{0} 数据库备份服务关闭", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
#endregion
#region 备份操作
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//定时操作
if (_time == "" || _time == null)
{
//没有保存上次本分时间,可能是第一次执行备份
//WriteLog(string.Format("{0} 开始备份操作", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
Bakup();
InitData();
//WriteLog(string.Format("{0} 备份操作完成", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
return;
}
string now = DateTime.Now.ToString("yyyy-MM-dd");
if (this.DateDiff(Convert.ToDateTime(now), Convert.ToDateTime(_time)) >= _Frequency)
{
//WriteLog(string.Format("{0} 开始备份操作", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
Bakup();
InitData();
//WriteLog(string.Format("{0} 备份操作完成", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
return;
}
}
#endregion
#region 方法
private bool Bakup()
{
string file = DateTime.Now.ToString("yyyyMMddHHmm");
string sql = string.Format("BACKUP DATABASE {1} TO DISK = '{0}.bak'", Path + "Bak\\" + file, _database);
SqlConnection con = new SqlConnection(_constr);
SqlCommand cmd = new SqlCommand(sql, con);
try
{
con.Open();
cmd.ExecuteNonQuery();
WriteBakDate();
return true;
}
catch(Exception e)
{
WriteLog(string.Format("{1} 备份数据库失败!原因可能是{0}", e.Message, DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
return false;
}
finally
{
con.Close();
}
}
/// <summary>
/// 计算2个时间的差值(单位:天)
/// </summary>
/// <param name="DateTime1"></param>
/// <param name="DateTime2"></param>
/// <returns></returns>
private int DateDiff(DateTime DateTime1, DateTime DateTime2)
{
int dateDiff = 0;
try
{
TimeSpan ts1 = new TimeSpan(DateTime1.Ticks);
TimeSpan ts2 = new TimeSpan(DateTime2.Ticks);
TimeSpan ts = ts1.Subtract(ts2).Duration();
dateDiff = ts.Days;
}
catch
{
}
return dateDiff;
}
private void WriteBakDate()
{
try
{
DataSet ds = new DataSet();
ds.ReadXml(Path + "\\Config.xml");
DataRow dr = ds.Tables[0].Rows[0];
dr.BeginEdit();
dr["Time"] = DateTime.Now.ToString("yyyy-MM-dd");
dr.EndEdit();
ds.WriteXml(Path + "Config.xml");
WriteLog(string.Format("{0} 备份数据库成功!", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
catch (Exception e)
{
WriteLog(string.Format("{1} 备份数据库成功!但写入配置文件最后备份时间项失败,原因可能是{0}", e.Message, DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
}
#endregion
#region 日志
private void WriteLog(string s)
{
FileStream fs = new FileStream(Path + "log.txt", FileMode.OpenOrCreate);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
try
{
string tmp = sr.ReadToEnd();
tmp += "\r\n" + s;
sw.Write(tmp);
}
catch
{ }
finally
{
sw.Close();
sr.Close();
fs.Close();
}
}
#endregion
}
}
6.然后再生成项目,不能使用F5,只能使用命令,这是BAT的命令:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe D:\C#\DataBaseBakupServer\DataBaseBakupServer\bin\Debug\DataBaseBakupServer.exe
net start DataBaseBakupServer
pause
net start DataBaseBakupServer
pause
注意:需要修改自己的目录路径
7.不多说了,希望小弟能在这里起到抛砖引玉的作用,网上关于这些的文章实在是很少啊,希望能和高手多多交流下