一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-UDA中处理事务
前文回顾
在之前的文章一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-使用UDA操纵SQL语句和一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-UDA中的委托与应用两篇文章中详细的介绍了如何使用UDA进行常规的业务进行操作,以及AgileEAS.NET平台中UDA的两种数据处理模式对比,以及基于懒惰模式的代理查询。
事务处理
我们知道在应用开发中,使用单SQL语句进行业务处理永远无法满足复杂的应用,一个业务可以需要2-N条SQL语句的配合才能完成,并且要求处理的数据保持一致性,也就是要求2-N语言要么全部执行成功,要么全部失败,不能产品执行一部分另一部分因为某些原因无法执行,造成数据的不一致。
.NET的Ado.NET为我们提供了事务处理机制,AgileEAS.ENT平台的统一数据访问(UDA)支持基于ADO.NET的事务处理机制,并对其进行了封装。
处理流程
标准的事务处理流程是在UDA的数据操作流程的基础上增加事务的打开、提交与回滚三个操作,流程如下:
AgileEAS.NET平台的UDA也为事务提供了一种懒得的处理模式,即事务托管执行,应用开发人员在这种模式中不用考虑连接的打和关闭,也不用考虑事务的开始、提交与回滚,而只需要关注应用业务就行。
事务处理的例子
假定我们需要处理一个商品的入库业务,涉及三个数据表,从商品字典有查出商品字典数据,向商品入库记录表和商品库存表同步写入数据,我们假定实现以单位为采购100单位的商品编码为“1AZ0002094” ,名称为“95%医用酒精”的业务,交易价格为12.5元,处理代码如下:
2 /// 标准流程的事务处理。
3 /// </summary>
4 public void DemoTransaction()
5 {
6 IDataAccessor accessor = UdaContext.DataAccessor;
7 accessor.DataConnection.Open();
8
9 try
10 {
11 try
12 {
13 (accessor.DataConnection as IConnection).BeginTransaction();
14
15 ParameterCollection pc = new ParameterCollection();
16 pc.Add("CODE", "1AZ0002094");
17
18 IDictionary<string, object> dc = accessor.QueryDictionary("SELECT * FROM dbo.PRODUCT where CODE= ?", pc);
19 string billCode = DateTime.Now.ToString("yyyyMMddHHmmss");
20
21 pc = new ParameterCollection();
22 pc.Add("BILLCODE", billCode);
23 pc.Add("CODE", dc["CODE"]);
24 pc.Add("NAME", dc["NAME"]);
25 pc.Add("SPEC", dc["SPEC"]);
26 pc.Add("UNIT", dc["UNIT"]);
27 pc.Add("PRICE", 12.5M);
28 pc.Add("NUMBER", 100);
29 pc.Add("OPERATOR", "james");
30 pc.Add("INTIME", DateTime.Now);
31
32 //入库记录
33 accessor.Execute("INSERT dbo.PIN(IDN,BILLCODE,CODE,NAME,SPEC,UNIT,PRICE,NUMBER,OPERATOR,INTIME) select isnull(max(idn),0)+1,?,?,?,?,?,?,?,?,? from dbo.PIN", pc);
34
35 //库存
36 pc = new ParameterCollection();
37 pc.Add("CODE", dc["CODE"]);
38 pc.Add("PRICE", 12.5M);
39
40 int storeRecords = (int)accessor.QueryScalar("SELECT count(*) FROM dbo.PSTORE where CODE= ? and PRICE = ?", pc);
41 if (storeRecords > 0)
42 {
43 accessor.QueryScalar("UPDATE dbo.PSTORE Set NUMBER=NUMBER +" + 100 + " where CODE= ? and PRICE = ?", pc);
44 }
45 else
46 {
47 pc = new ParameterCollection();
48 pc.Add("CODE", dc["CODE"]);
49 pc.Add("NAME", dc["NAME"]);
50 pc.Add("SPEC", dc["SPEC"]);
51 pc.Add("UNIT", dc["UNIT"]);
52 pc.Add("PRICE", 12.5M);
53 pc.Add("NUMBER", 100);
54
55 accessor.Execute("INSERT dbo.PSTORE(IDN,CODE,NAME,SPEC,UNIT,PRICE,NUMBER) select isnull(max(idn),0)+1,?,?,?,?,?,? from dbo.PSTORE", pc);
56 }
57
58 (accessor.DataConnection as IConnection).CommitTransaction();
59 System.Console.WriteLine("事务已成功提交。");
60 }
61 catch
62 {
63 (accessor.DataConnection as IConnection).RollbackTransaction();
64 System.Console.WriteLine("事务已回滚。");
65 throw;
66 }
67 }
68 finally
69 {
70 accessor.DataConnection.Close();
71 }
72 }
使用事务委托
上面的单码需要应用开发人管理数据库的打开、关闭,还得处理事务的开始、提交与回滚业务,每个都如些进行处理,容易出错,程序也不是很简洁,在AgileEAS.NET平台的统一数据访问(UDA)中提供了一种更为简洁的事务处理处理方式事务委托,我们定义了TransactionHandler及TransactionHandler2两个事务委托:
/// <summary> /// 定义数据库操作的事务处理委托。该委托将代表客户执行数据库事务,这样使用者不需要考虑事务的开始和结束。 /// </summary> /// <param name="Accessor">数据访问器对象。</param> public delegate void TransactionHandler(IDataAccessor Accessor); /// <summary> /// 定义数据库操作的事务处理委托。该委托将代表客户执行数据库事务,这样使用者不需要考虑事务的开始和结束。 /// </summary> /// <param name="Accessor">数据访问器对象。</param> /// <param name="parameters">委托参数。</param> public delegate void TransactionHandler2(IDataAccessor Accessor, params object[] parameters);
在IDataAccessor接口中定义了使用这两个委托的事务委托方法TransactionExecute(托管执行),闲话不说了,我们来使用TransactionExecute改造以上代码:
2 /// 委托方式的事务。
3 /// </summary>
4 public void DemoTransaction()
5 {
6 IDataAccessor accessor = UdaContext.DataAccessor;
7 try
8 {
9 accessor.TransactionExecute(new TransactionHandler(this.InternalSaveData));
10 System.Console.WriteLine("事务已成功提交。");
11 }
12 catch
13 {
14 System.Console.WriteLine("事务已回滚。");
15 }
16 }
17
18 /// <summary>
19 /// 事务代理方法。
20 /// </summary>
21 /// <param name="accessor"></param>
22 void InternalSaveData(IDataAccessor accessor)
23 {
24 ParameterCollection pc = new ParameterCollection();
25 pc.Add("CODE", "1AZ0002094");
26
27 IDictionary<string, object> dc = accessor.QueryDictionary("SELECT * FROM dbo.PRODUCT where CODE= ?", pc);
28 string billCode = DateTime.Now.ToString("yyyyMMddHHmmss" +"_1");
29
30 pc = new ParameterCollection();
31 pc.Add("BILLCODE", billCode);
32 pc.Add("CODE", dc["CODE"]);
33 pc.Add("NAME", dc["NAME"]);
34 pc.Add("SPEC", dc["SPEC"]);
35 pc.Add("UNIT", dc["UNIT"]);
36 pc.Add("PRICE", 12.5M);
37 pc.Add("NUMBER", 100);
38 pc.Add("OPERATOR", "james");
39 pc.Add("INTIME", DateTime.Now);
40
41 //入库记录
42 accessor.Execute("INSERT dbo.PIN(IDN,BILLCODE,CODE,NAME,SPEC,UNIT,PRICE,NUMBER,OPERATOR,INTIME) select isnull(max(idn),0)+1,?,?,?,?,?,?,?,?,? from dbo.PIN", pc);
43
44 //库存
45 pc = new ParameterCollection();
46 pc.Add("CODE", dc["CODE"]);
47 pc.Add("PRICE", 12.5M);
48
49 int storeRecords = (int)accessor.QueryScalar("SELECT count(*) FROM dbo.PSTORE where CODE= ? and PRICE = ?", pc);
50 if (storeRecords > 0)
51 {
52 accessor.QueryScalar("UPDATE dbo.PSTORE Set NUMBER=NUMBER +" + 100 + " where CODE= ? and PRICE = ?", pc);
53 }
54 else
55 {
56 pc = new ParameterCollection();
57 pc.Add("CODE", dc["CODE"]);
58 pc.Add("NAME", dc["NAME"]);
59 pc.Add("SPEC", dc["SPEC"]);
60 pc.Add("UNIT", dc["UNIT"]);
61 pc.Add("PRICE", 12.5M);
62 pc.Add("NUMBER", 100);
63
64 accessor.Execute("INSERT dbo.PSTORE(IDN,CODE,NAME,SPEC,UNIT,PRICE,NUMBER) select isnull(max(idn),0)+1,?,?,?,?,?,? from dbo.PSTORE", pc);
65 }
66 }
有关本例子所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:https://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本文代码下载:UDA.Demo3.rar。
链接
一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录
QQ群:116773358
作者:魏琼东
出处:http://www.cnblogs.com/eastjade
关于作者:有13年的软件从业经历,专注于中小软件企业软件开发过程研究,通过在技术与管理帮助中小软件企业实现技术层面开源节流的目的。熟悉需求分析、企业架构、项目管理。现主要从事基于AgileEAS.NET平台的技术咨询工作,主要服务于医疗卫生、铁路、电信、物流、物联网、制造、零售等行业。如有问题或建议,请多多赐教!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过mail.james@qq.com 联系我,也可以加入QQ群:113723486、199463175、116773358、116773358、212867943、147168308、59827496、193486983、15118502和大家共同讨论,非常感谢。