[小技術(shù)應(yīng)用]使用windows服務(wù)備份數(shù)據(jù)
1.使用VS2005創(chuàng)建windows服務(wù),從工具箱的組件表當(dāng)中拖動一個Timer對象到這個設(shè)計表面上 (注意: 要確保是從組件列表而不是從Windows窗體列表當(dāng)中使用Timer) ,修改“.Designer.cs”文件,將timer組件修改為繼承自System.Timers.Timer
2.在設(shè)計器右鍵選擇添加安裝程序,設(shè)置serviceInstaller1組件的屬性:
1) ServiceName = My Sample Service
2) StartType = Automatic (開機(jī)自動運行)
3. 設(shè)置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,然后在里面寫一些數(shù)據(jù)庫操作的代碼,下面是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;
//間隔天數(shù)
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 初始化服務(wù)信息
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”應(yīng)該來自“System.Timers命名空間”(“System.Timers.Timer”才能在Windows服務(wù)程序中正常定時調(diào)用),但是現(xiàn)在Timer卻繼承至“System.Windows.Forms.Timer”。所以得修改“.Designer.cs”文件
#region 啟動和關(guān)閉
protected override void OnStart(string[] args)
{
// TODO: 在此處添加代碼以啟動服務(wù)。
timer1.Enabled = true;
timer1.Start();
WriteLog(string.Format("{0} 數(shù)據(jù)庫備份服務(wù)啟動", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
protected override void OnStop()
{
// TODO: 在此處添加代碼以執(zhí)行停止服務(wù)所需的關(guān)閉操作。
timer1.Stop();
timer1.Enabled = false;
WriteLog(string.Format("{0} 數(shù)據(jù)庫備份服務(wù)關(guān)閉", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
#endregion
#region 備份操作
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//定時操作
if (_time == "" || _time == null)
{
//沒有保存上次本分時間,可能是第一次執(zhí)行備份
//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} 備份數(shù)據(jù)庫失敗!原因可能是{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} 備份數(shù)據(jù)庫成功!", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
catch (Exception e)
{
WriteLog(string.Format("{1} 備份數(shù)據(jù)庫成功!但寫入配置文件最后備份時間項失敗,原因可能是{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;
//間隔天數(shù)
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 初始化服務(wù)信息
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”應(yīng)該來自“System.Timers命名空間”(“System.Timers.Timer”才能在Windows服務(wù)程序中正常定時調(diào)用),但是現(xiàn)在Timer卻繼承至“System.Windows.Forms.Timer”。所以得修改“.Designer.cs”文件
#region 啟動和關(guān)閉
protected override void OnStart(string[] args)
{
// TODO: 在此處添加代碼以啟動服務(wù)。
timer1.Enabled = true;
timer1.Start();
WriteLog(string.Format("{0} 數(shù)據(jù)庫備份服務(wù)啟動", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
protected override void OnStop()
{
// TODO: 在此處添加代碼以執(zhí)行停止服務(wù)所需的關(guān)閉操作。
timer1.Stop();
timer1.Enabled = false;
WriteLog(string.Format("{0} 數(shù)據(jù)庫備份服務(wù)關(guān)閉", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
#endregion
#region 備份操作
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//定時操作
if (_time == "" || _time == null)
{
//沒有保存上次本分時間,可能是第一次執(zhí)行備份
//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} 備份數(shù)據(jù)庫失敗!原因可能是{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} 備份數(shù)據(jù)庫成功!", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
}
catch (Exception e)
{
WriteLog(string.Format("{1} 備份數(shù)據(jù)庫成功!但寫入配置文件最后備份時間項失敗,原因可能是{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.不多說了,希望小弟能在這里起到拋磚引玉的作用,網(wǎng)上關(guān)于這些的文章實在是很少啊,希望能和高手多多交流下
浙公網(wǎng)安備 33010602011771號