框架通用 Excel 導入模塊長期服務於 SQL Server,但隨 SQLite 單機版應用增多,逐條自動提交事務導致萬條數據寫入極慢。本文實現 事務性批量導入,並攻克事務中「查詢判斷是否存在」導致鎖表超時的難題,提速數十倍。
基類 FrmImportExcelData 定義兩個委托事件,將事務創建與單行保存邏輯外置給調用者:
public delegate bool SaveDataHandler(DataRow dr, DbTransaction trans); public delegate DbTransaction CreateTransactionHandler(); public event SaveDataHandler OnDataSave; public event CreateTransactionHandler OnCreateTransaction;
if (OnCreateTransaction != null) transaction = OnCreateTransaction();
foreach (DataRow dr in dt.Rows) {
if (OnDataSave != null) {
bool success = OnDataSave(dr, transaction);
if (success) itemCount++;
}
worker.ReportProgress(...);
}
if (transaction != null) transaction.Commit();
private void btnImport_Click(...) {
var dlg = new FrmImportExcelData();
dlg.OnDataSave += ExcelData_OnDataSave;
dlg.OnCreateTransaction += dlg_OnCreateTransaction;
dlg.OnRefreshData += ExcelData_OnRefreshData;
dlg.ShowDialog();
}
DbTransaction dlg_OnCreateTransaction() => BLLFactory<DrugDetail>.Instance.CreateTransaction();
bool ExcelData_OnDataSave(DataRow dr, DbTransaction trans) {
string drugNo = dr["藥品編碼"].ToString();
string drugName = dr["藥品名稱"].ToString();
if (string.IsNullOrEmpty(drugNo) && string.IsNullOrEmpty(drugName)) return false;
var info = new DrugDetailInfo { DrugNo = drugNo, DrugName = drugName, ... };
return BLLFactory<DrugDetail>.Instance.Insert(info, trans); // 統一事務
}
錯誤做法:直接 `SELECT ...` 會因事務鎖表導致超時。
正確做法:使用 事務連接對象 執行查詢,框架基類所有查詢接口均新增 `DbTransaction trans = null` 參數:
bool dlg_OnDataSave(DataRow dr, DbTransaction trans) {
string model = dr["裝備型號"].ToString();
if (string.IsNullOrEmpty(model)) return false;
// 關鍵:傳入 trans 參數,使用事務連接查詢
var info = BLLFactory<PlaneModel>.Instance.FindSingle($"PlaneModel='{model}'", trans);
if (info != null) {
info.PlaneNote = dr["保障特點"].ToString(); ...
return BLLFactory<PlaneModel>.Instance.Update(info, info.ID, trans);
} else {
info = new PlaneModelInfo { PlaneModel = model, ... };
return BLLFactory<PlaneModel>.Instance.Insert(info, trans);
}
}
// IDAL 接口 int GetRecordCount(string condition, DbTransaction trans = null); bool IsExistRecord(string condition, DbTransaction trans = null); bool IsExistKey(Hashtable table, DbTransaction trans = null); T FindSingle(string condition, DbTransaction trans = null); // BLL 基類實現 public virtual bool Insert(T obj, DbTransaction trans = null) => baseDal.Insert(obj, trans); public virtual bool Update(T obj, object pk, DbTransaction trans = null) => baseDal.Update(obj, pk, trans);
此優化使 SQLite 批量導入從「不可忍受」變為「秒級完成」,並保持代碼結構清晰、事務邊界可控。