用Microsoft.net实现数据库事务<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
摘要:了解.net的Pet Shop 2企业版本是怎样帮助企业解决实际中的业务问题,Net Pet Shop
验证了怎样利用.net框架和Visual Studio.net来开发最佳的企业级系统。就如Sun公司的Java™ Pet Store J2EE™ Blueprint application,它也是一个最佳的系统实现。
.NET 宠物店程序开发于2001年11月,它描述了.Net开发者怎样利用.net框架和Visual Studio.net开发最佳的系统。下面关于宠物店和原来的J2EE宠物店的讨论涉及了企业级系统的一些特性,如可靠性和伸缩性。对于一个系统要部署成企业级,一定要考虑它的安全性、可靠性、可伸缩性、可管理性以及与已有的系统和数据进行协同的工作。以前版本的宠物店系统所表现出来的成本优势、性能和开发效率在.Net平台上仍然存在。本文通过描述了.Net支持的其他的企业级需求,从而把宠物店的讨论引向深入。
许多企业都有他们存在于不同系统中的分布的数据,比如存货数据在一个存货控制系统中,而客户资料数据却在他们的CRM系统中。我们的系统需要处理这些不同数据库中的数据,并且保证数据的更改在这些系统中正确进行,要达到这些要求,我们需要跨数据库的事务处理。
宠物店企业级版本是为了展示.net平台上的技术可以很好的支持那些企业级系统的特性。它在处理现实世界中存在的数据存储方面提供了一个可靠的、可伸缩的系统。宠物店企业级版本处理这样的一些情形,如客户数据存在于一个服务器上的客户数据库系统中,而客户定单数据存在于物理上不同的服务器上的一个不同的数据库系统中,这样的情形在许多机构中是一个普遍的现象。
为了保证客户数据和客户定单数据永远是正确的,需要一个包含这两个数据源的分布式系统。本文讨论了在.net企业级系统中处理事务的不同机制,给出了每种机制的示例代码,讨论了一些最佳做法。本文中的代码是用c#写成的,但所有的方法和技术一样适用于VB.net.
本文所讨论的跨多个数据库的分布式事务对于一个系统来说早已被证实具有优良的性能和伸缩性。这里还测试了.net平台上的几种事务机制的性能,详细的列举和描述了它们的结果。从这些结果中,我们可以清楚的看到.net从功能上和性能上都提供了优秀的企业级事务支持。
本文还包含了宠物店的一些介绍,它的初始架构和实现,以及为了支持企业级特性对它的一些改动。还详细讨论了不同的事务方式和他们的测试性能结果图。
请参阅how Sun Microsystems' Java Pet Store J2EE BluePrint Application was implemented using Microsoft .NET.
假设一个可以在线订购宠物的电子商务企业,当你进入系统后,你可以浏览、查询从犬类到爬行动物的各种类型的宠物。
一个典型的宠物店系统包括:
l 主页 -当你打开系统后载入的页面。
l 类别浏览 –顶层有五种类别,每种类别下面都有若干产品。
l 产品 –当系统里面的一个产品被选种时,产品的属性就被显示出来,典型的如公或者母。
l 产品明细 –每种产品属性的详细说明,如照片、价格和库存数量。
l 购物车 –允许客户去维护一个购物车(增加、删除、更新数量)。
l 校验 –只读地显示一个购物车信息。
l 登录定向 –当用户在校验页面上选择继续的时候,如果他还没有登录,则会定向到登录页面。
l 验证登录 –当登录被验证后,就会转到信用卡信息和订购地址信息页面。
l 确认定单 –定单和客户地址信息被显示出来等待确认。
l 提交定单 –最后的一个步骤,在这里定单被提交到数据库。
宠物店的一个例子如图:
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 323.25pt; HEIGHT: 212.25pt" alt="" type="#_x0000_t75"><img o:href="file:///E:\download\net\Implementing%20Database%20Transactions%20with%20Microsoft%20_NET.files\rightframe.files\psent.files\psent1.gif" src="/Develop/ArticleImages/25/25152/CSDN_Dev_Image_2004-3-3950290.gif"><font size="3"></font></shape>
图1:.net宠物店
。net宠物店的总体逻辑架构如图:
<shape id="_x0000_i1026" style="WIDTH: 356.25pt; HEIGHT: 339pt" alt="" type="#_x0000_t75"><img o:href="file:///E:\download\net\Implementing%20Database%20Transactions%20with%20Microsoft%20_NET.files\rightframe.files\psent.files\psent2.gif" src="/Develop/ArticleImages/25/25152/CSDN_Dev_Image_2004-3-3950292.gif"><font size="3"></font></shape>
图2:.net宠物店逻辑架构
有三个逻辑层:表示层、中间层、数据层,这三层可以使不同特征的分布式系统进行清晰的部署,逻辑层被装成一个.net装配(用C#类库实现),对数据库的访问是用一个类来处理所有的与SQL Server Managed provider的交互,用存储过程来存取数据,这个系统利用了.net实现了完全的逻辑上的三层架构,表现了.net平台上的最佳实践。
<shape id="_x0000_i1027" style="WIDTH: 356.25pt; HEIGHT: 215.25pt" alt="" type="#_x0000_t75"><img o:href="file:///E:\download\net\Implementing%20Database%20Transactions%20with%20Microsoft%20_NET.files\rightframe.files\psent.files\psent3.gif" src="/Develop/ArticleImages/25/25152/CSDN_Dev_Image_2004-3-3950294.gif"><font size="3"></font></shape>
图3:.net宠物店系统的物理部署图
程序架构
图4是用来表现我们的设计的详细图,我们可以看到宠物店每层的实现和交互细节
<shape id="_x0000_i1028" style="WIDTH: 234pt; HEIGHT: 414.75pt" alt="" type="#_x0000_t75"><img o:href="file:///E:\download\net\Implementing%20Database%20Transactions%20with%20Microsoft%20_NET.files\rightframe.files\psent.files\psent4.gif" src="/Develop/ArticleImages/25/25152/CSDN_Dev_Image_2004-3-3950296.gif"><font size="3"></font></shape>
图4:架构设想
数据库
数据库有如下的表
表名 |
解释 |
Account |
基本的客户信息 |
BannerData |
存储广告和标语信息 |
Category |
类别信息 (如鱼类、犬类、猫类等). |
Inventory |
产品存货信息 |
Item |
每个产品详细信息 |
LineItem |
定单明细 |
Orders |
客户下的定单,一个定单包含一个或一个以上定单明细 |
OrderStatus |
定单状态 |
Product |
产品目录 ,每个产品包含一个或者一个以上属性,典型的属性如公母。 |
Profile |
客户定制的信息 |
Signon |
客户登录信息 |
Supplier |
有关供应方信息 |
表格1:数据库表名
原有的.net宠物店中Order类的addOrder方法所调用的存储过程中用到了数据库事务,这个调用涉及到了四个表的数据,需要定义ACID属性。因为如果一个定单被创建,库存数据需要被调整。存储过程利用了一个xml文档做参数,插入定单数据、定单明细,插入定单状态数据,更新定单里涉及到的产品的库存数据,我们的目标是从单一数据库架构变为分布式数据库架构,也就是客户、产品和库存数据存在一个数据库里面,定单存在于另外的一个数据库中。为了达到这个目标,我们需要转移到一个企业服务型架构,这是唯一的一种可以控制分布式事务和提供两阶段的提交的机制。为了转移到企业服务级,我们需要考察几种情形的影响:
l 引入企业服务类库,但是用数据库事务/ADO.NET事务
l 引入企业服务类库,利用它来控制事务
l 引入企业服务类库,利用它来控制分布式事务
为了实现分布式事务,我们需要修改addOrder方法和数据库交互的方式,在单一的数据库情形下,我们利用了一个存储过程;对于分布式,我们需要变为两个存储过程,每个数据库一个,我们意识到原先的存储过程在最后表之间用了连接,现在这些表存在于不同的数据库中,所以我们最好还是把这些实现放到中间层中,用动态生成SQL语句。
为了显示引入企业服务类库对于每个组件的影响,我们设计了.net宠物店的几个版本:
l 用最初的.net宠物店v1.5作为基础
l 利用ADO.NET事务的.net宠物店
l 使用企业服务类库和ADO.NET事务(企业服务的事务属性设置为”不支持”)
l 利用企业服务的事务(事务属性在Order组件被设置为”需要”,ADO.NET的事务去掉)
l 利用企业服务来处理分布式事务
<shape id="_x0000_i1029" style="WIDTH: 303.75pt; HEIGHT: 577.5pt" alt="" type="#_x0000_t75"><img o:href="file:///E:\download\net\Implementing%20Database%20Transactions%20with%20Microsoft%20_NET.files\rightframe.files\psent.files\psent5.gif" src="/Develop/ArticleImages/25/25152/CSDN_Dev_Image_2004-3-3950298.gif"></shape>
图5:宠物店数据库模型
<shape id="_x0000_i1030" style="WIDTH: 316.5pt; HEIGHT: 333pt" alt="" type="#_x0000_t75"><img o:href="file:///E:\download\net\Implementing%20Database%20Transactions%20with%20Microsoft%20_NET.files\rightframe.files\psent.files\psent6.gif" src="/Develop/ArticleImages/25/25152/CSDN_Dev_Image_2004-3-39502910.gif"></shape>
图6:定单数据库模型
.net开发者可以使用四种机制:
l 数据库事务
l ADO.NET事务
l ASP.NET事务
l 企业服务级事务
每种机制在以下的几方面有各自的优势和劣势:性能、代码数量、部署设置。许多开发者都很熟悉数据库的事务,在这种情形下,中间层调用数据库的存储过程,存储过程中开始一个事务,如果每个语句都执行成功则提交,如果有错误发生时就会回滚。
如果你的事务需要几个调用,例如,你需要插入多个定单明细到一个表中,但不想用一个xml文档或者传递一个很长的字符串,这些都需要在存储过程中被解析,你可以用ADO.NET事务机制。ADO.NET事务允许你在当前的连接上创建一个事务上下文,运行对数据库的多次调用,在最后或者提交或者回滚。
ASP.NET事务是在Web应用程序的页面层工作,你只要简单的在页面属性中加一个” Transaction="Required”,这样在页面中的事件处理都作为页面整个事务的一部分,任何处理出现错误,则所有的处理都将回滚。
企业服务型组件通过资源管理器和分布事务控制器(DTC)来实现事务,当ASP.NET,一个数据库的调用或者事务中涉及到的其他资源发生错误或者异常时,整个事务将被回滚,企业服务建立在COM+技术的基础上来处理事务,熟悉COM+的开发者应该理解企业服务。
应该被提到实现一个事务的这些不同方式之间可能是互斥的,如果你混合使用数据库事务和企业服务事务,你就会得到一个错误,这是因为你会得到重复的提交,你在企业服务中可能提交一个在数据库事务中已经提交了的事务,这样已经没有事务上下文来进行提交动作了。同样的问题如在数据库事务中提交了一个事务,但在企业服务中却因为在系统中发生异常而回滚。