寫了一個windows服務安裝在本機中,使服務能在我看不見的地方對資料庫進行悄悄的修改。
你可以在網上搜尋如何建立及安裝一個windows服務,會搜尋出來一大堆對你有協助的東西,我就簡單的說一下吧。
我電腦win7旗艦版,用的vs2010(經過上篇博文所說的過程,我是真心不行弄單位的電腦了) 和SQL Server 2008
建立無非就是在建立中找到windows☞windows服務☞命名及儲存路徑
我是在後台手敲了一個timer,你也可以在像如下所說的
在安裝時只要在設計頁右鍵☞添加安裝程式,會自動出現
修改serviceInstaller1的Automatic屬性為Automatic,ServiceName屬性自訂個名稱;
修改serviceProcessInsertaller1的LocalSystem屬性為LocalSystem;
對著你的服務右鍵產生,然後在你的電腦中找到你服務的儲存位置☞服務名稱的檔案夾☞bin☞Debug☞添加兩個txt檔案,分別命名為安裝服務和卸載服務,內容分別為
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe 名稱.exe
pause 和
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u 名稱.exe
pause
然後將兩個.txt檔案的尾碼名稱改為.bat ,安裝時直接雙擊安裝檔案就行(懶人都這麼幹),卸載也一樣。
我得服務叫Service1(我知道我很懶~~嘻嘻),在Service1.Designer.cs中定義了個時間控制項
private System.Timers.Timer timer1;
private void InitializeComponent() { this.timer1 = new System.Timers.Timer(); components = new System.ComponentModel.Container(); this.ServiceName = "Service1"; ((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit(); // // timer1(毫秒數) // 300000 五分鐘 // 3600000 一小時 // 86400000 一天 this.timer1.Interval = 300000; this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed); ((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit(); //缺少這句會是服務不可啟動哦,似乎報錯說服務缺少依賴什麼的 }
並且將InitializeComponent()方法完善。
下列是Service1服務的基礎作業碼
DataTable datatable = new DataTable(); private Object rLock = new Object();//鎖 int nCurRowIndex = 0; //全域變數 int times = 0; //對資料庫操作的次數 public Service1() { InitializeComponent(); InitService(); } /// <summary> /// 初始化服務參數 /// </summary> private void InitService() { base.AutoLog = false; base.CanShutdown = true; base.CanStop = true; base.CanPauseAndContinue = true; base.ServiceName = "Service1"; //這個名字很重要,設定不一致會產生 1083 錯誤哦! } /// <summary> /// 服務開始 /// </summary> /// <param name="args"></param> protected override void OnStart(string[] args) { using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true)) { sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "Start."); } this.timer1.Enabled = true; } /// <summary> /// 服務結束 /// </summary> protected override void OnStop() { using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true)) { sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "Stop."); } this.timer1.Enabled = false; } /// <summary> /// 服務暫停 /// </summary> protected override void OnPause() { //服務暫停執行代碼 base.OnPause(); } protected override void OnContinue() { //服務恢複執行代碼 base.OnContinue(); } protected override void OnShutdown() { //系統即將關閉執行代碼 base.OnShutdown(); } private void Elapsed() { GetAllWikipedia(); } private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //執行SQL語句或其他動作 GetAllWikipedia();//達到時間走這個 }
對於資料的查詢很簡單,就像是普通.net程式操作資料庫一樣
/// <summary> /// 查詢表 /// </summary> /// <returns></returns> public DataTable ChaXun() { SqlConnection con = new SqlConnection("Data Source=. ;Initial Catalog=HDQYMS;Persist Security Info=True;User ID=sa;Password=sasa"); string sql = "select * from Wikipedia"; using (SqlCommand cmd = new SqlCommand(sql, con)) { DataSet ds = new DataSet(); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(ds); con.Close(); DataTable dt = ds.Tables[0]; times++; using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true)) { sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "第" + times + "次擷取資料庫中Wikipedia表"); } return dt; } }
此處開啟了兩個線程來工作
//這個是線程函數 private void DoProcess() { bool flag = true; while (flag) { Thread nonParameterThreadA = new Thread(new ThreadStart(NonParameterRun));//建立線程 nonParameterThreadA.Name = "ThreadA"; nonParameterThreadA.Start(); Thread nonParameterThreadB = new Thread(new ThreadStart(NonParameterRun)); nonParameterThreadB.Name = "ThreadB"; nonParameterThreadB.Start(); flag = false; } } /// <summary> /// 不帶參數的啟動方法 /// </summary> public void NonParameterRun() { while (true) { lock (rLock)//鎖 { DataRow rRow = GetRowToProcess();//擷取行 if (rRow == null) { Thread.Sleep(300000); nCurRowIndex = 0; break; } //這裡處理rRow, else { try { Update(rRow);//真正要進行的工作 Thread.Sleep(10); } catch (Exception ex) { using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true)) { sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "發生異常" + ex); } OnStop(); } } } } }
如是我要對資料庫進行操作的表。我得服務要達到的目的就是在開啟以後沒隔一段時間就要查詢一下資料庫中表的內容其中LinkAddress是網址,我要根據這個網址去網上查詢網頁的源碼,然後看一下我得QutsideAddress1,2,3這三個外鏈是否還有效,有效時就標識√,無效標識×,就這樣。
但是我不得不說再做的時候遇到了幾個問題
①在沒有給Thread.Sleep(300000);時我的線程開啟了兩個,他們就會將我需要的操作全部執行兩遍,如果開啟了三個,那麼就是全部執行三遍 ̄□ ̄||
解決辦法目前先是讓線程休眠吧,有時間再弄。(誰又好的辦法,或者知道我哪裡寫錯了一定要告訴我哈~感激不盡....)
②因為在對外鏈的判斷結束之後還要有對資料的修改操作,本想用個事務或者其他的使他們共同完成,可是加了多線程之後這個似乎就不好實現,或者說我沒有找到方法,此處沒有貼出具體的作業碼。我還是用的很笨的方式修改,不提也罷。
③我感覺放上了線程之後工作的時間似乎沒有什麼太大的改善啊,好像還是需要依賴於網速的~而且不知道是不是我沒有定義這兩個線程的優先順序的問題,B線程都是要比A線程執行的多,大概四五個B線程執行完之後會有一個A的影子~
④因為第一次做windows服務,調試還是很讓我頭疼的,百度說啟動後在程式中找到調試☞附加到進程☞√顯示所有使用者的進程☞重新整理☞找到你的服務☞附加 即可進行調試,但是我找到的我得服務全是灰色的啊,根本不可能附加進程啊,所以我還是採用了一個最笨的辦法,就是寫工作日誌,那裡出錯找哪裡,(媽媽再也不用擔心我得學習 ̄□ ̄||)