Winform开发框架里面使用事务操作的原理及介绍

在很多情况下,事务是个很有用的东西,可以把一系列的操作组合成一个原子粒度的操作,一旦组合中某个地方出错,可以整个干净的进行滚回,不会留下脏数据;除此之外,事务还能提高批量操作的效率,如在本地SQLite数据库里面,批量插入1万条数据,那么使用事务和没有使用事务,速度上至少差别几十到上百倍的差异。既然事务有完整性和速度性的差异,因此,基于上述原因,我们在很多情况下最好使用事务进行操作。本文主要介绍在开发框架中如何整合事务的操作,并介绍在各个分层中的事务使用案例。

由于我介绍的相关框架,主要是采用了微软的Enterprise
Library的数据库访问模块,因此它能够很好抽象各种数据库的事务,以适应各种不同数据库的事务处理。使用微软的Enterprise
Library模块,可以很好支持SQLSever、Oracle、Mysql、Access、SQLite等数据库。

1、数据访问层中的事务操作

1.1 数据访问层的事务接口定义

由于使用事务操作,因此在底层的模块里面,也就是这里的数据访问层,一般需要一个事务对象的参数。如下代码是一个数据访问层的接口定义。


    /// <summary>
/// 数据访问层的接口
/// </summary>
public interface IBaseDAL<T> where T : BaseEntity
{
/// <summary>
/// 插入指定对象到数据库中
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="trans">事务对象</param>
/// <returns>执行成功返回True</returns>
bool Insert(T obj, DbTransaction trans = null);

/// <summary>
/// 根据指定对象的ID,从数据库中删除指定对象
/// </summary>
/// <param name="key">指定对象的ID</param>
/// <param name="trans">事务对象</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
bool Delete(object key, DbTransaction trans = null);

/// <summary>
/// 更新对象属性到数据库中
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="primaryKeyValue">主键的值</param>
/// <param name="trans">事务对象</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
bool Update(T obj, object primaryKeyValue, DbTransaction trans = null);

/// <summary>
/// 查询数据库,检查是否存在指定ID的对象
/// </summary>
/// <param name="key">对象的ID值</param>
/// <param name="trans">事务对象</param>
/// <returns>存在则返回指定的对象,否则返回Null</returns>
T FindByID(object key, DbTransaction trans = null);

.....................//其他操作

}

从上面的代码上,我们可以看到,里面的增删改查等操作,最后都带一个trans的事务对象参数,这个参数默认为null,也就是可选参数的做法,这个方法就提供了两个重载的方法供我们使用。

看到这里,可能有些人提出疑问,为什么查找方法也传入事务对象,这个因为事务是一个排斥性操作,一旦启动了事务,可能这个表的其他操作会被锁定,但在这个事务内操作确实可以允许的,如果你使用SQLite这种单机版的数据库,在一个地方采用事务操作一个表,在事务内部接着不使用事务进行表的任何操作将不会被允许,数据库提示出错信息的。

基于这个原因,所有表操作的接口,都应该提供事务性的操作接口,也就是提供一个事务性的对象参数。在接口的实现里面,判断事务对象是否为空,然后进行相应的处理即可。

1.2 在DAL层自定义函数的事务操作

由于在IBaseDAL里面已经定义了很多事务性的接口,因此数据访问层的基类里面也已经实现了很多相关的基础操作。

因此数据访问层DAL层里面,如自己定义的实现函数,调用这些基础函数进行处理就可以了。自定义函数对事务的操作处理,代码如下所示。


        /// <summary>
/// 调整客户的组别
/// </summary>
/// <param name="customerId">客户ID</param>
/// <param name="groupIdList">客户分组Id集合</param>
/// <returns></returns>
public bool ModifyCustomerGroup(string customerId, List<string> groupIdList)
{
bool result = false;
DbTransaction trans = base.CreateTransaction();
if (trans != null)
{
string sql = string.Format("Delete from T_CRM_CustomerGroup_Customer where Customer_ID=‘{0}‘ ", customerId);
base.SqlExecute(sql, trans);

foreach (string groupId in groupIdList)
{
sql = string.Format("Insert into T_CRM_CustomerGroup_Customer(Customer_ID,CustomerGroup_ID) values(‘{0}‘, ‘{1}‘) ", customerId, groupId);
base.SqlExecute(sql, trans);
}

try
{
trans.Commit();
result = true;
}
catch
{
trans.Rollback();
throw;
}
}
return result;
}

2、业务逻辑层的事务操作


业务逻辑层BLL层是对数据访问层的更高一层的封装,它也相应提供相应的事务对象接口,以方便外部的调用。

它的业务类里面,自定义函数对事务的调用操作如下所示。


        /// <summary>
/// 把报价单转换为销售订单
/// </summary>
/// <param name="quotationNo">报价单编号</param>
/// <returns></returns>
public bool ConvertToOrder(string orderNo, int userId)
{
bool result = false;

DbTransaction trans = baseDal.CreateTransaction();
if (trans != null)
{
SellInfo sellInfo = ConvertSellInfo(orderNo, userId, trans);
List<OrderDetailInfo> detailList = new List<OrderDetailInfo>();
if (sellInfo != null)
{
detailList = ConvertOrderDetal(sellInfo, orderNo, trans);
}

bool success = BLLFactory<Sell>.Instance.Insert(sellInfo, trans);
if (success)
{
foreach (OrderDetailInfo info in detailList)
{
BLLFactory<OrderDetail>.Instance.Insert(info, trans);
}
}

try
{
trans.Commit();
result = true;
}
catch
{
trans.Rollback();
throw;//重新抛出异常
}
}
return result;
}

另一例子如下所示。


        /// <summary>
/// 删除报价单及明细信息
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool DeleteQuotationRelated(string id)
{
bool result = false;
DbTransaction trans = CreateTransaction();
if (trans != null)
{
QuotationInfo info = baseDal.FindByID(id, trans);
if (info != null)
{
List<QuotationDetailInfo> detailList = BLLFactory<QuotationDetail>.Instance.FindByOrderNo(info.HandNo, trans);
foreach (QuotationDetailInfo detailInfo in detailList)
{
BLLFactory<QuotationDetail>.Instance.Delete(detailInfo.ID, trans);
}

//最后删除主表订单数据
baseDal.Delete(id, trans);

try
{
trans.Commit();
result = true;
}
catch (Exception ex)
{
trans.Rollback();
LogTextHelper.Error(ex);
throw;
}
}
}
return result;
}
}

3、Winform界面层对事务的调用


由于Winform界面层,直接调用BLL层的相应接口,进行数据的操作的,因此我们也可以在界面层创建相应的事务对象,然后在界面层操作事务。

界面层调用事务处理,操作代码如下所示。


            using (DbTransaction trans = BLLFactory<Function>.Instance.CreateTransaction())
{
try
{
if (trans != null)
{
bool sucess = BLLFactory<Function>.Instance.Insert(mainInfo, trans);
if (sucess)
{
FunctionInfo subInfo = null;
int sortCodeIndex = 1;

#region 子功能操作
if (chkAdd.Checked)
{
subInfo = CreateSubFunction(mainInfo);
subInfo.SortCode = (sortCodeIndex++).ToString("D2");
subInfo.ControlID = string.Format("{0}/Add", mainInfo.ControlID);
subInfo.Name = string.Format("添加{0}", mainInfo.Name);

BLLFactory<Function>.Instance.Insert(subInfo, trans);
}
if (chkDelete.Checked)
{
subInfo = CreateSubFunction(mainInfo);
subInfo.SortCode = (sortCodeIndex++).ToString("D2");
subInfo.ControlID = string.Format("{0}/Delete", mainInfo.ControlID);
subInfo.Name = string.Format("删除{0}", mainInfo.Name);
BLLFactory<Function>.Instance.Insert(subInfo, trans);
}
......................//其他事务操作
#endregion

trans.Commit();
ProcessDataSaved(this.btnSave, new EventArgs());

//this.DialogResult = System.Windows.Forms.DialogResult.OK;
MessageDxUtil.ShowTips("保存成功");
}
else
{
MessageDxUtil.ShowTips("保存失败");
}
}
}
catch (Exception ex)
{
if (trans != null)
{
trans.Rollback();
}

LogTextHelper.Error(ex);
MessageDxUtil.ShowError(ex.Message);
}
}

以上就是我对不同分层中使用事务对象进行各种操作的处理,由于事务对象会对表进行某种锁定操作,因此数据库的整体性能可能有所降低,但是在保证某种组合操作的原子性,以及批量数据库操作这两种方式,该出手时还是要出手,这样能更好提高完整性和处理的高效性。

Winform开发框架里面使用事务操作的原理及介绍,码迷,mamicode.com

时间: 2024-10-13 11:19:51

Winform开发框架里面使用事务操作的原理及介绍的相关文章

【Redis源码剖析】 - Redis之事务的实现原理

原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/51262268 今天为大家带来Redis中事务部分的源码分析.Redis的事务机制允许将多个命令当做一个独立的单元运行,主要包括multi.exec.watch.unwatch.discard五个相关命令.如果你还不熟悉这几个命令,可以先看看我的另一篇文章[Redis学习笔记(七)] Redis中的事务 本文所讲述的内容主要涉及redis.h和multi.c两个源文件,依据惯例,

Winform开发框架中工作流模块之审批会签操作(2)

前面随笔介绍了请假申请单和报销申请单两个不同的业务表单的流程处理,一个是单表信息,一个包含明细的主从表信息,后者包含了条件流程的处理,在流程审批中,一般还有一种流程处理就是会签的操作,会签处理是几个审批步骤中审批人同时处理是否通过的,一般同时通过即为通过.本篇随笔介绍工作流中的会签处理过程. 1.会签流程定义 会签是指创建一个或多个子流程供相关人员进行审批,等待全部人员完成处理后再次回到主流程上,然后决定是否继续流转到下一个流程步骤上去,一般的申请单的主流程如下所示. 这里设置的会签处理就是其中

Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(2)

本篇继续上篇<Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(1)>来对Winform开发框架之存储过程的支持进行介绍,上篇主要介绍了SQLServer和Oracle两种数据库对常规存储过程的编写和对比,本篇主要介绍如何在C#里面,如何对这些存储过程进行调用,并获取到对应的数据类型,如输出参数,单个数据记录,多个数据记录等情况.最后在完成实现功能的基础上,对这些实现进行演化提炼,并扩展到我的WInform开发框架里面,实现功能重用.代码简化的目的. 1.数据访问接口的定义

Winform开发框架之简易工作流设计(转自 伍华聪博客)

Winform开发框架之简易工作流设计 一讲到工作流,很多人第一反应就是这个东西很深奥,有时候又觉得离我们较为遥远,确实完善的工作流设计很多方面,而正是由于需要兼顾很多方面,一般通用的工作流都难做到尽善尽美.微软也提供了几个版本的WF框架支持,也有一些厂家是基于这个框架基础上开发的工作流应用. 以前由于项目的需要,参与过一些工作流的项目开发,其中有些是基于我简易工作流的原理上进行拓展的,包括一个广州市各区县使用的行业审批业务平台,由于基于自己的流程处理,界面设计.流程流转等方面可以很好符合客户需

基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作

由于一个客户朋友的需求,需要我的Winform开发框架支持国产达梦数据库的操作,这个数据库很早就听过,但是真正一般项目用的很少,一般在一些特殊的项目可能需要用到.由于我的Winform开发框架,是基于Enterprise Library的数据访问层的实现,因此增加一个数据库的支持很容易,本文介绍如何在框架层面上支持这种神秘的国产数据库-达梦数据库. 1.达梦数据库的简单介绍 达梦数据库管理系统是达梦公司推出的具有完全自主知识产权的高性能数据库管理系统,简称DM.达梦数据库管理系统的最新版本是7.

Winform开发框架中实现同时兼容多种数据库类型处理

在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适应性和强壮型.还有一种情况,由于业务数据库的不断膨胀或者方便数据库的切割隔离,有时候也会把不同的业务数据库进行分拆,如权限提供数据库,客户关系管理数据库,工作流程数据库,企业营运数据库等等,因此在一个系统里面,同时使用2个或者以上的数据库的情况也是有的. 在我较早期的一篇随笔<Winform开发框架

Winform开发框架中的综合案例Demo

在实际的系统开发中,我们往往需要一些简单的的案例代码,基于此目的我把Winform开发框架中各种闪光点和不错的功能,有些是我们对功能模块的简单封装,而有些则是引入了一些应用广泛的开源组件进行集成使用,因此把它们做了一个Demo进行展示,以方便我们随时了解和参考,并能够快速应用相应的场景到具体的项目中. 1.闪屏展示界面及主体界面 在很多系统里面,提供一个设计不错的图片作为程序界面展示的效果是挺不错的,这个小程序也不例外,基本上整合了一些WInform界面常用的各种功能. 而整个案例的界面的界面以

asp.net中Winform开发框架之数据即时更新的实现

在开篇之前,首先介绍一下Winform开发框架中的界面层的继承关系,首先我把所有窗体区分为三类,一类是普通的窗体,一类编辑窗体,还有一类是列表显示窗体.窗体的集成可以封装处理很多东西,良好的封装和继承,可以为我们提高效率,减少重复代码,它的作用不再在此讨论和强调. 采用窗体继承,极大程度上统一了界面,并且对常用的界面操作,提供了良好的封装,如基础数据编辑.新增窗体积累封装了对回车.方向键.数据刷新.异常处理.数据检查.数据保存.数据更新等接口,为窗体的数据处理提供了很大的方便性.而数据查询显示窗

[转载]Winform开发框架之统计图表的实现

在前面的一些随笔中,介绍了不少我的Winform框架的特性,上篇随笔<Winform开发框架之通用高级查询模块>对其中的通用高级模块进了一个整理说明,本篇继续介绍Winform开发框架重要的一个特性之统计图表的实现.统计图表在很多项目都可能用到,集成到框架中,更方便大家对一些图表项目的设计理解以及功能的重用.在一般的传统的框架中,可以采用ZedGraph开源控件或者微软自带的MSChart进行图表设计,DevExpress控件套件有自己的图表控件,本篇主要介绍基于DevExpress控件的图表