SQLite数据库作为一般单机版软件的数据库,是非常优秀的,我目前单机版的软件产品线基本上全部替换Access作为优选的数据库了,在开发过程中,有时候需要批量写入数据的情况,发现传统的插入数据模式非常慢,几千条数据的写入或者更新可能需要好几分钟时间,而SqlServer则相同的操作可能几秒即可,有无更好的方法来提高它的响应速度呢?答案是有的,就是采用事务提交,默认SQLite的数据库插入操作,如果没有采用事务的话,它每次写入提交,就会触发一次事务操作,而这样几千条的数据,就会触发几千个事务的操作,这就是时间耗费的根源。本文通过详细代码介绍如何使用事务来提高整个批量插入数据的速度,并以实际的Winform开发框架中的字典管理模块的批量插入功能来进行介绍,通过前后速度的对比,使得事务操作提高响应速度更有说服力。
由于一些项目需要,字典管理模块需要批量录入数据,因此改善了我的《Winform开发框架》中的字典管理模块,在字典管理模块增加一个批量添加的功能,如下所示。
对一些诊断的数据录入,一般情况下都可能是几千条的数据,还有可能更多的一些分类字典,那么如果每次都需要等待几分钟或者几十分钟,那么这样的响应体验肯定很差。
为了提高响应速度,我这里使用了事务操作,整个事务操作是基于EnterpriseLibray类库的数据库操作,由于我已经在框架的基类中做了封装,因此我们这里看到整个处理过程即可。
其中MyRegion里面的代码就是遍历每行的数据,构造数据字典对象和排序号,然后调用InsertDictData函数进行数据的录入。其中InsertDictData函数的代码是
/// <summary> /// 使用事务参数,插入数据,最后统一提交事务处理 /// </summary> /// <param name="dictData">字典数据</param> /// <param name="seq">排序</param> /// <param name="trans">事务对象</param> private void InsertDictData(string dictData, string seq, DbTransaction trans) { if (!string.IsNullOrWhiteSpace(dictData)) { DictDataInfo info = new DictDataInfo(); info.Editor = LoginID; info.LastUpdated = DateTime.Now; info.DictType_ID = this.txtDictType.Tag.ToString(); info.Name = dictData.Trim(); info.Value = dictData.Trim(); info.Remark = this.txtNote.Text.Trim(); info.Seq = seq; bool succeed = BLLFactory<DictData>.Instance.Insert(info, trans); } }
整个插入功能按钮的处理全部代码如下所示。
private void btnOK_Click(object sender, EventArgs e) { string[] arrayItems = this.txtDictData.Lines; int intSeq = -1; int seqLength = 3; string strSeq = this.txtSeq.Text.Trim(); if (int.TryParse(strSeq, out intSeq)) { seqLength = strSeq.Length; } if (arrayItems != null && arrayItems.Length > 0) { DbTransaction trans = BLLFactory<DictData>.Instance.CreateTransaction(); if (trans != null) { try { #region MyRegion foreach (string strItem in arrayItems) { if (this.radSplit.Checked) { if (!string.IsNullOrWhiteSpace(strItem)) { string[] dataItems = strItem.Split(new char[] { ',', ',', ';', ';', '/', '、' }); foreach (string dictData in dataItems) { #region 保存数据 string seq = ""; if (intSeq > 0) { seq = (intSeq++).ToString().PadLeft(seqLength, '0'); } else { seq = string.Format("{0}{1}", strSeq, intSeq++); } InsertDictData(dictData, seq, trans); #endregion } } } else { #region 保存数据 if (!string.IsNullOrWhiteSpace(strItem)) { string seq = ""; if (intSeq > 0) { seq = (intSeq++).ToString().PadLeft(seqLength, '0'); } else { seq = string.Format("{0}{1}", strSeq, intSeq++); } InsertDictData(strItem, seq, trans); } #endregion } } #endregion trans.Commit(); ProcessDataSaved(this.btnOK, new EventArgs()); MessageDxUtil.ShowTips("保存成功"); this.DialogResult = DialogResult.OK; } catch (Exception ex) { trans.Rollback(); LogTextHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); } } } }
上面的批量插入,经过前后的测试,2千条数据批量插入SQLite数据库,需要大概3~4分钟左右,如果采用了事务操作,则在1~2秒内写入完成,速度提高不知道多少倍。如果是操作数据比较多的,强烈建议使用事务进行操作,可以给客户很好的体验效果。
如果嫌上面的代码复杂,可以看下面的讲解代码可能就明白了
using (DbTransaction dbTrans = conn.BeginTransaction()) { using (DbCommand cmd = conn.CreateCommand()) { cmd.CommandText = "INSERT INTO MyTable(MyValue) VALUES(?)"; DbParameter Field1 = cmd.CreateParameter(); cmd.Parameters.Add(Field1); for (int n = 0; n < 100000; n++) { Field1.Value = n + 100000; cmd.ExecuteNonQuery(); } } }
上面是一种比较简单原始的事务操作,如果批量插入数据,同样能够起到一样的效果。