业务逻辑层的设计(五)——事务脚本模式介绍
2013-11-20 21:19
344 查看
经过了几个月的奋斗,我终于又可以坐下来写点东西了。
业务逻辑层设计到此为止已经有第五篇了,其实我最想写的就是事务脚本这篇了,因为它最实在,适合各级别的开发人员,毫不夸张地讲,在企业应用的开发中,我觉得可以一招吃遍天下了。
事务脚本模式的思路:
通俗一点来说,就是你点了一个按钮触发一个事件时,这个事件中将处理一系列的命令,这些命令组合在一起形成一个事务,然后又可以在另一个按钮事件中重新将他们组合起来,形成一个新的事务。
比如,我的保存事件中执行一个事务,1检查一些状态;2保存一些数据;
然后我在另一个提交事件中也执行一个事务,1检查一些状态;2保存一些数据;3流程提交;
伪代码表示
看完以上伪代码我们发现保存按钮的时候我们没有启用事务,
而在提交按钮的时候我们开启了事务,需要保证数据的保存和提交在一个事务中。
优势:
简单,容易上手,DAO(数据访问对象)的重用可能性高,强于经典的三层。
不管你是在浪迹职场咪咪笑笑的老程序员,还是楚楚可怜的新程序员,都会深深地爱上这种模式。
对于新程序员来说,在软件架构设计师的对框架的支持下,我们写SQL的时候不必关注事务的管理,可以集中精力对付功能的实现上。
对于老程序员来说,它十分灵活,可以将DAO改造成Command(命令)然后发挥各种设计模式,因为将事务管理移到了业务层,并且去掉了讨厌的ADO.NET事务相关的参数,使得老鸟发挥各种设计模式的时候更加随心所欲。
DAO或者Command摆脱了事务的困扰后,它的设计高度符合高内聚的设计原则,一个Command(命令)只做一件事情,可以放心地重用或者修改其他人写类。
也因为高内聚,单元测试时先测试每一个DAO,然后再测试事件,做到自底向上,逐步求精,这也充分符合了面向对象的测试。
劣势:
事物总是有两面性的,就因为它的优点做一件事情建立一个Command类,所以项目经历了1期、2期、3期。。。功能的扩展以后,你会发现项目中将会有一堆Command类,和一群Manager类,所以你得小心地给他们分门别类的存放。
与使用O/RM相比,还是需要写SQL语句,虽然可以重用数据访问的代码,因为没有领域模型,所以很多业务规则依然没办法重用。
尽管它有许多劣势,但与经典的三层相比,它可以处理更加复杂的业务需求,
经典的三层一旦遇到事务密集的项目,业务层和数据访问层就会黏在一起了,如果对三层进行改良,把事务管理提上来,放在业务层,然后思维模式稍加改变,就变成了事务脚本。
所以,如果你的需求不只是做一些简单增删改的页面,需要使用事务犹如家常便饭,然后又觉得引入O/RM会对现有的项目产生影响,那么你的开发框架可以考虑向事务脚本演化了。
事务管理的实现原理:
将事务管理从数据访问层上提,放到业务层,并且消除ADO.NET的事务参数。
如何实现?我们需要将一个数据库连接贯穿整个事件(或者是每个WEB请求),在事件中所有DAO都将使用同一个数据库连接。
我们只要利用CallContext类把数据库连接放到一个请求上下文中,DAO需要操作数据库时从CallContext中取出连接即可。
WEB应用程序中也可以直接使用HttpContext。
在老项目中最好是自己对DBHelper作扩展,简单地使用继承就能在不修改原来代码的基础上扩展出新的DBHelper。
如果你准备新开发一个系统,那么可以选择使用Spring或者Spring.NET,参看事务管理的那部分,将事务托管给Spring来管理。
事务脚本模式实战:
某一个按钮事件,可以发现事务由N个命令组成,然后AOGTypeFlowCreate.Init小用了一下工厂模式,然而一系列的命令访问数据库的操作都在同一个事务中。
某一个命令,以构造函数初始化参数,用只读属性返回值,于是所有的命令都有一个统一的方法Run(),实战中我用的命令模式的简化版。
操作数据库的database是由DBHelper扩展而来,如何扩展就见仁见智,根据上面提到的原理不难实现。
下面是使用微软企业库实现的版本
这里并没有给出我具体怎么扩展框架的代码,非常遗憾,但是解决思路才是最重要的不是吗?
对自己没有信心的话,完全可以引入Spring.NET框架使用AdoTemplate来解决问题,学习框架or自己动手,只要能解决问题都可行。
业务逻辑层设计到此为止已经有第五篇了,其实我最想写的就是事务脚本这篇了,因为它最实在,适合各级别的开发人员,毫不夸张地讲,在企业应用的开发中,我觉得可以一招吃遍天下了。
事务脚本模式的思路:
通俗一点来说,就是你点了一个按钮触发一个事件时,这个事件中将处理一系列的命令,这些命令组合在一起形成一个事务,然后又可以在另一个按钮事件中重新将他们组合起来,形成一个新的事务。
比如,我的保存事件中执行一个事务,1检查一些状态;2保存一些数据;
然后我在另一个提交事件中也执行一个事务,1检查一些状态;2保存一些数据;3流程提交;
伪代码表示
public void Save(){ Dao1 dao1=new Dao1(); dao1.IsExists();//检查一些东西 Dao2 dao1=new Dao2(); dao2.Save();//保存一些数据 } public void Submit(){ try{ BeginTran(); Dao1 dao1=new Dao1(); dao1.IsExists();//检查一些东西 Dao2 dao1=new Dao2(); dao2.Save();//保存一些数据 Dao3 dao3=new Dao3(); dao3.GoToNextFlow();//流程提交 Commit(); }catch(){ Rollback(); } }
看完以上伪代码我们发现保存按钮的时候我们没有启用事务,
而在提交按钮的时候我们开启了事务,需要保证数据的保存和提交在一个事务中。
优势:
简单,容易上手,DAO(数据访问对象)的重用可能性高,强于经典的三层。
不管你是在浪迹职场咪咪笑笑的老程序员,还是楚楚可怜的新程序员,都会深深地爱上这种模式。
对于新程序员来说,在软件架构设计师的对框架的支持下,我们写SQL的时候不必关注事务的管理,可以集中精力对付功能的实现上。
对于老程序员来说,它十分灵活,可以将DAO改造成Command(命令)然后发挥各种设计模式,因为将事务管理移到了业务层,并且去掉了讨厌的ADO.NET事务相关的参数,使得老鸟发挥各种设计模式的时候更加随心所欲。
DAO或者Command摆脱了事务的困扰后,它的设计高度符合高内聚的设计原则,一个Command(命令)只做一件事情,可以放心地重用或者修改其他人写类。
也因为高内聚,单元测试时先测试每一个DAO,然后再测试事件,做到自底向上,逐步求精,这也充分符合了面向对象的测试。
劣势:
事物总是有两面性的,就因为它的优点做一件事情建立一个Command类,所以项目经历了1期、2期、3期。。。功能的扩展以后,你会发现项目中将会有一堆Command类,和一群Manager类,所以你得小心地给他们分门别类的存放。
与使用O/RM相比,还是需要写SQL语句,虽然可以重用数据访问的代码,因为没有领域模型,所以很多业务规则依然没办法重用。
尽管它有许多劣势,但与经典的三层相比,它可以处理更加复杂的业务需求,
经典的三层一旦遇到事务密集的项目,业务层和数据访问层就会黏在一起了,如果对三层进行改良,把事务管理提上来,放在业务层,然后思维模式稍加改变,就变成了事务脚本。
所以,如果你的需求不只是做一些简单增删改的页面,需要使用事务犹如家常便饭,然后又觉得引入O/RM会对现有的项目产生影响,那么你的开发框架可以考虑向事务脚本演化了。
事务管理的实现原理:
将事务管理从数据访问层上提,放到业务层,并且消除ADO.NET的事务参数。
如何实现?我们需要将一个数据库连接贯穿整个事件(或者是每个WEB请求),在事件中所有DAO都将使用同一个数据库连接。
我们只要利用CallContext类把数据库连接放到一个请求上下文中,DAO需要操作数据库时从CallContext中取出连接即可。
WEB应用程序中也可以直接使用HttpContext。
在老项目中最好是自己对DBHelper作扩展,简单地使用继承就能在不修改原来代码的基础上扩展出新的DBHelper。
如果你准备新开发一个系统,那么可以选择使用Spring或者Spring.NET,参看事务管理的那部分,将事务托管给Spring来管理。
事务脚本模式实战:
某一个按钮事件,可以发现事务由N个命令组成,然后AOGTypeFlowCreate.Init小用了一下工厂模式,然而一系列的命令访问数据库的操作都在同一个事务中。
public void Appiont(decimal? schemeid,decimal? aogtype) { try { BeginTransaction(); GetCurrToProviderFlowCMD getcurrToProviderCMD = new GetCurrToProviderFlowCMD(schemeid); getcurrToProviderCMD.Run(); //验证流程1是否已开始 if (getcurrToProviderCMD.CurrFlow > 0) throw new Exception("流程1已经开始,无法重新指定!"); GetCurrToStorageFlowCMD getcurrToStorageCMD = new GetCurrToStorageFlowCMD(schemeid); getcurrToStorageCMD.Run(); //验证流程2是否已开始 if (getcurrToStorageCMD.CurrFlow > 0) throw new Exception("流程2已经开始,无法重新指定!"); AOGTypeFlowDeleteCMD aogtypeflowdelCMD = new AOGTypeFlowDeleteCMD(schemeid); aogtypeflowdelCMD.Run(); //删除流程任务 AOGTypeAppointCMD aogtypeappointCMD = new AOGTypeAppointCMD(schemeid, aogtype); if (aogtypeappointCMD.Run() == 0) throw new DataBaseExecuteInvalidException(); //指定到货方式 if (aogtype != null) { IAOGTypeFlowCreateCMD aogtypeflowcreateCMD = AOGTypeFlowCreate.Init(schemeid, aogtype); if (aogtypeflowcreateCMD.Run() == 0) throw new DataBaseExecuteInvalidException(); //插入新的流程任务 } Commit(); } catch (Exception ex) { RollBack(); throw new Exception(ex.Message); } }
某一个命令,以构造函数初始化参数,用只读属性返回值,于是所有的命令都有一个统一的方法Run(),实战中我用的命令模式的简化版。
操作数据库的database是由DBHelper扩展而来,如何扩展就见仁见智,根据上面提到的原理不难实现。
public class GetCurrToProviderFlowCMD : BaseCommand { private decimal? _schemeid; private int _currFlow; public int CurrFlow { get { return _currFlow; } } public GetCurrToProviderFlowCMD(decimal? schemeid) { _schemeid = schemeid; } public int Run() { StringBuilder builder = new StringBuilder(); builder.Append("select currflow from oproviderflow where schemeid=:schemeid"); OracleParameter prm = new OracleParameter(":schemeid", OracleDbType.Decimal); prm.Value = _schemeid; string res = database.ExecuteScalar(builder.ToString(), prm); _currFlow = res != "" ? Convert.ToInt32(res) : 0; return 1; } }
下面是使用微软企业库实现的版本
public class FirstCommand:BaseCommand { private DataTable _table; private int _id; public DataTable Table { get { return _table; } } public FirstCommand(int id) { this._id = id; } public int Run() { IDbCommand cmd=dbHelper.GetSqlStringCommand("select * from SYS_RESOURCE where ID=:resid"); dbHelper.AddInParameter(cmd, ":resid", DbType.Int32, _id); _table = dbHelper.ExecuteDataTable(cmd); return 1; } }
这里并没有给出我具体怎么扩展框架的代码,非常遗憾,但是解决思路才是最重要的不是吗?
对自己没有信心的话,完全可以引入Spring.NET框架使用AdoTemplate来解决问题,学习框架or自己动手,只要能解决问题都可行。
相关文章推荐
- js显示时间
- Java Hour 46 SLF4J
- 注册——登录实战演习 (使用java web应用的三层架构实现)
- 从最大似然到EM算法浅解
- c++学习之--排序4-直接选择排序
- 【OpenCV】数字图像灰度直方图
- JAVA多线程学习1
- iOS6下实现滑动返回
- HIbernate学习笔记(一) 了解hibernate并搭建环境建立第一个hello world程序
- 简单工厂模式
- Codeforces Div.2 213 C Matrix (预处理+哈希)
- c++学习之--排序3-快速排序
- category
- python 专题十五 集合
- 关于Certificate、Provisioning Profile、App ID的介绍及其之间的关系-转
- 指针2
- java web开发中的三层架构原理图
- 长沙现场赛A题
- VS2010中的C++产生各种“随机数”的方法(第1讲)
- c++学习之--排序2-直接插入排序