1:先上圖,再介紹亮點功能:
1:增加(Truncate Table)清表再插入功能:
清掉再插,可以保證兩個庫的數據一致,自己很喜歡這個功能。
2:信息欄增加紅色部分:
黑色的信息太多,有時候錯誤信息被淹陌,分拆出來單獨紅色塊標識錯誤信息,清晰一些。
3:增加保存所有的配置及配置還原:
之前只保存數據庫鏈接的配置,為了第4點,包起了所有的配置,包括表名等。
4:增加自啟動參數,用於定時功能的開機啟動:
自啟動參數為 - true 或 - 1,下一版本會處理成服務,支持重啟電腦後繼續服務。
5:解決軟件穩定性(自動退出)問題。
記得我發布ASP.NET Aries框架的時候,有個演示地址:http://aries.cyqdata.com 。
由於總有個人別刪除用戶或數據或修改登陸密碼,為了防止此種情況:
我把DBImport放到服務器,同時開啟了定時功能,以為可以一勞永逸了。
結果軟件運行運行著,就自動退出了,然後又得手工執行一次。
所以目前在執行的方案,鎖定了文件的只讀屬性,來避免用戶修改數據。
今天剛好想起來,於是就想到要解決它了,於是就有了以下的內容:
單獨運行軟件,開啟定時功能,然後出去溜達一圈,回頭再看結果:
多次確認後,而且問題不單純:
A:卡住沒反應。
B:拋異常定義到Application.Run(單獨運行時表現直接退出軟件)。
開啟了”IntelliTrace事件和調用信息“:
F5運行,拋:“嘗試讀取或寫入受保護的內存。這通常指示其他內存已損壞”。
我以為找到問題,結果是掉坑裡。
1:當一個方法返回數組T[] GetList()時,拋這個異常。 2:當Dictionary添加一個數組Add(key,T[])時,拋這個異常。 3:當方法的參數為:public MDataTable Select(params object[] selectColumns) 這種數組時,拋這個異常。
好吧,這數組是哪裡得罪了微軟,要被它這麼欺負。
改了半天代碼,把T[]數組的代碼全改成List<T>,一般又一步,走向正常運行。
後來沒折了,畢竟有些公開的方法有params參數不好改,只好把選項改成“僅IntelliTrace事件”。
運行,等出Bug後,點一下全部中斷:
然後就可以看到執行的事件了:
結合著自己記錄的錯誤信息:
回頭審了一下代碼,終於發現一個Bug:
if (isGoOn) { using (SqlBulkCopy sbc = new SqlBulkCopy(con, (keepID ? SqlBulkCopyOptions.KeepIdentity : SqlBulkCopyOptions.Default) | SqlBulkCopyOptions.FireTriggers, sqlTran)) { sbc.BatchSize = 100000; sbc.DestinationTableName = SqlFormat.Keyword(mdt.TableName, DalType.MsSql); sbc.BulkCopyTimeout = AppConfig.DB.CommandTimeout; foreach (MCellStruct column in mdt.Columns) { sbc.ColumnMappings.Add(column.ColumnName, column.ColumnName); } sbc.WriteToServer(mdt); } } if (_dalHelper == null) { con.Close(); con = null; } else if (isCreateDal) { _dalHelper.EndTransaction(); _dalHelper.Dispose(); }
這段代碼,在異常的時候,鏈接關閉不了,重點它還是開了事務的,沒想到都老江湖了,百密還是有一輸。
於是運行久了,連接池耗盡,加上事務卡死雙重打擊,界面就進入長時間卡死不動了。
找到問題修正就好了,關閉鏈接的放到Try的finally去:
finally { if (_dalHelper == null) { con.Close(); con = null; } else if (isCreateDal) { _dalHelper.EndTransaction(); _dalHelper.Dispose(); } }
畢竟當年創業寫微博粉絲精靈的時候,就遇到過了:
對於Winform軟件,不要在線程裡操作UI,不要相信:StartForm.CheckForIllegalCrossThreadCalls = false;
於是,把所有的代碼都改成主線程委托調用的方式,類似以下代碼:
private delegate void SetTextHandle(string id, string value); private void ThreadSetText(string id, string value) { this.Controls.Find(id, true)[0].Text = value; } private void SetText(string id, string value) { if (this.InvokeRequired) { this.Invoke(new SetTextHandle(ThreadSetText), new object[] { id, value }); } else { ThreadSetText(id, value); } }
好了,至此,穩定性的問題解決了,周末愉快!