spring.net nhibernate 分布布式事务(下)

摘自: http://www.cnblogs.com/GoodHelper/archive/2010/07/30/SpringNetDistributedTransaction2.html

Spring.NET实用技巧4——NHibernate分布式事务(下)

  

  上篇,我们已实现了在同一应用程序下的分布式事务——即多Dao层+同Service层,每个Dao对应一个数据库,一个Service调用多个Dao。但是在一些特定的子系统较多的项目中,开发人员是无法访问到某个子系统的数据库,这就意味着不能通过增加Dao层来实现分布式事务。正如一个银行的软件系统,记录了客户的账户信息和存款金额,北京的分公司和上海的分公司分别有自己的数据库和软件系统。现在,要实现北京的系统向上海的系统转账,然而各自作为开发人员来说,没有足够的权限去访问对方的数据库,但是可以提供Web Service的方式去访问其系统服务。这样,我们就需要实现基于Web Service的分布式事务。

  实现基于Web Service的分布式事务的方法比较多,可以通过.NET企业服务的方式。但是为了更好的实现,我们选择WCF作为一个分布式应用程序框架。WCF在实现分布式事务中有它的优越之处。其思路在于启动MSDTC服务,将客户端的事务以流的方式传递到服务器端,在服务器端执行通过时,客户端再提交事务,相反则回滚事务。

  我们模仿上篇的场景做一个demo,并使用上篇的Dao和Domain。

  

  一、启动MSDTC服务。

  二、Service层

  ①.Customer

  

CustomerManager

    publicinterface ICustomerManager     {         CustomerInfo Get(object id);
        object Save(CustomerInfo entity);
        void Update(CustomerInfo entity);     }
    publicclass CustomerManager : ICustomerManager     {         private ICustomerDao Dao { get; set; }
        public CustomerInfo Get(object id)         {             return Dao.Get(id);         }
        publicobject Save(CustomerInfo entity)         {             return Dao.Save(entity);         }
        publicvoid Update(CustomerInfo entity)         {             if (entity.Money >3000)             {                 thrownew Exception("订金上限");             }             Dao.Update(entity);         }     }

  

Service.xml

<?xml version="1.0" encoding="utf-8" ?><objects xmlns="http://www.springframework.net">
  <object id="transactionManager"         type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate21">     <property name="DbProvider" ref="DbProvider"/>     <property name="SessionFactory" ref="NHibernateSessionFactory"/>   </object>
  <object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">     <property name="TransactionManager" ref="transactionManager"/>     <property name="TransactionAttributeSource">       <object type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data"/>     </property>   </object>
  <object id="BaseTransactionManager"  type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data" abstract="true">     <property name="PlatformTransactionManager" ref="transactionManager"/>     <property name="TransactionAttributes">       <name-values>          <add key="*" value="PROPAGATION_REQUIRED"/>       </name-values>     </property>   </object>
  <object id="Customer.CustomerManager" parent="BaseTransactionManager">     <property name="Target">       <object type="Customer.Service.Implement.CustomerManager, Customer.Service">         <property name="Dao" ref="Customer.CustomerDao"/>       </object>     </property>   </object>
</objects>

  ②.Order

  

OrderManager

    publicinterface IOrderManager     {         object Save(OrderInfo entity);     }
    publicclass OrderManager : IOrderManager     {         public IOrderDao Dao { get; set; }
        publicobject Save(OrderInfo entity)         {             return Dao.Save(entity);         }     }

Service.xml

<?xml version="1.0" encoding="utf-8" ?><objects xmlns="http://www.springframework.net">
  <object id="transactionManager"         type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate21">     <property name="DbProvider" ref="DbProvider"/>     <property name="SessionFactory" ref="NHibernateSessionFactory"/>   </object>
  <object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">     <property name="TransactionManager" ref="transactionManager"/>     <property name="TransactionAttributeSource">       <object type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data"/>     </property>   </object>
  <object id="BaseTransactionManager"  type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data" abstract="true">     <property name="PlatformTransactionManager" ref="transactionManager"/>     <property name="TransactionAttributes">       <name-values>          <add key="*" value="PROPAGATION_REQUIRED"/>       </name-values>     </property>   </object>
  <object id="Order.OrderManager" parent="BaseTransactionManager">     <property name="Target">       <object type="Order.Service.Implement.OrderManager, Order.Service">         <property name="Dao" ref="Order.OrderDao"/>       </object>     </property>   </object>
</objects>

  三、服务契约和Host。

  1、契约

  作为服务契约,需要启用Session,并且设置TransactionFlowOption的等级为Allowed或Mandatory来接收客户端事务流。

  作为契约的实现部分,需要设置TransactionScopeRequired为true来启用事务作用域。

  ①.Customer

CustomerContract

    [ServiceContract(SessionMode = SessionMode.Required)]     publicinterface ICustomerContract     {         [OperationContract]         [TransactionFlow(TransactionFlowOption.Allowed)]         CustomerInfo Get(object id);
        [OperationContract]         [TransactionFlow(TransactionFlowOption.Allowed)]         object Save(CustomerInfo entity);
        [OperationContract]         [TransactionFlow(TransactionFlowOption.Allowed)]         void Update(CustomerInfo entity);     }
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]     publicclass CustomerServer : ICustomerContract     {         public ICustomerManager Manager { get; set; }
        [OperationBehavior(TransactionScopeRequired =true)]         public CustomerInfo Get(object id)         {             return Manager.Get(id);         }
        [OperationBehavior(TransactionScopeRequired =true)]         publicobject Save(CustomerInfo entity)         {
            return Manager.Save(entity);         }
        [OperationBehavior(TransactionScopeRequired =true)]         publicvoid Update(CustomerInfo entity)         {             Manager.Update(entity);         }

  ②.Order

  

IOrderContract

    [ServiceContract(SessionMode = SessionMode.Required)]     publicinterface IOrderContract     {         [OperationContract]         [TransactionFlow(TransactionFlowOption.Allowed)]         object Save(OrderInfo entity);     }
   [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]     publicclass OrderServer : IOrderContract     {         public IOrderManager Manager { get; set; }
        [OperationBehavior(TransactionScopeRequired =true)]         publicobject Save(OrderInfo entity)         {             return Manager.Save(entity);         }     }

  2、配置

  然而,Spring.NET针对NHibernate的Session管理使用的是OSIV模式(Open Session In View),即使用httpModule去拦截HTTP请求,在每次请求开始时打开Session作用域(SessionScope),最后在请求结束后关闭SessionScope。这样一来,在客户端每请求一次时都会打开SessionScope,在请求结束会关闭SessionScope,然后当请求结束后再去处理分布式就会提示“无法使用已释放对象”的错误。所以说,OSIV是无法正常管理分布式事务的。出于上述原因,我们决定在Global.asax的配置,在Session(这里的Session是ASP.NET中的Session)启动时候打开SessionScope,在Session结束时关闭SessionScope。这样分布式事务就会与SessionScope同步了。

  最后,在配置appSettings节点增加     <add key="Spring.Data.NHibernate.Support.SessionScope.SessionFactoryObjectName" value="NHibernateSessionFactory"/>

  另外配置WCF的binding时需要选择一种支持Session的binding(如wsHttpBinding)并且将binding中的transactionFlow属性设置为true。

  

Global.asax

    publicclass Global : System.Web.HttpApplication     {
        protectedvoid Application_Start(object sender, EventArgs e)         {             log4net.Config.XmlConfigurator.Configure();         }
        protectedvoid Session_Start(object sender, EventArgs e)         {             SessionScope sessionScope =new SessionScope("appSettings", typeof(SessionScope), false);             sessionScope.Open();             HttpContext.Current.Session["SessionScope"] = sessionScope;         }
                protectedvoid Session_End(object sender, EventArgs e)         {             SessionScope sessionScope = HttpContext.Current.Session["SessionScope"] as SessionScope;             if (sessionScope !=null)             {                 sessionScope.Close();             }         }
    }

  ①.Customer

 

Web.config

<?xml version="1.0" encoding="utf-8"?><configuration>
 

..............
<!--spring配置-->   <spring xmlns="http://www.springframework.net">     <parsers>       <parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"/>       <parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data"/>     </parsers>     <context>       <resource uri="config://spring/objects"/>
      <!--Dao-->       <resource uri="assembly://Customer.Dao/Customer.Dao.Config/Dao.xml"/>       <!--Service-->       <resource uri="assembly://Customer.Service/Customer.Service.Config/Service.xml"/>
    </context>     <objects xmlns="http://www.springframework.net"              xmlns:aop="http://www.springframework.net/aop">
      <object id="Customer.Host" type="Customer.Host.Implement.CustomerServer, Customer.Host">         <property name="Manager" ref="Customer.CustomerManager"/>       </object>
    </objects>   </spring>
  <appSettings>     <add key="Spring.Data.NHibernate.Support.SessionScope.SessionFactoryObjectName" value="NHibernateSessionFactory"/>   </appSettings>
  <system.web>     <compilation debug="true" targetFramework="4.0"/>
    <httpModules>       <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>     </httpModules>
  </system.web>   <system.serviceModel>     <services>       <service name="Customer.Host">         <endpoint address="" binding="wsHttpBinding" bindingConfiguration="ServerBinding" contract="Customer.Host.ICustomerContract"/>         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>       </service>     </services>     <bindings>       <wsHttpBinding >         <binding name="ServerBinding" transactionFlow="true">         </binding>       </wsHttpBinding>     </bindings>     <behaviors>       <serviceBehaviors>         <behavior>           <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->           <serviceMetadata httpGetEnabled="true"/>           <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->           <serviceDebug includeExceptionDetailInFaults="true"/>         </behavior>       </serviceBehaviors>     </behaviors>     <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>   </system.serviceModel><system.webServer>     <modules runAllManagedModulesForAllRequests="true"/>   </system.webServer>   </configuration>

<%@ ServiceHost Language="C#" Debug="true" Service="Customer.Host" Factory="Spring.ServiceModel.Activation.ServiceHostFactory"%>

  ②.Order

  

Web.config

<?xml version="1.0" encoding="utf-8"?><configuration>
  ..........
  <!--spring配置-->   <spring xmlns="http://www.springframework.net">     <parsers>       <parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"/>       <parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data"/>     </parsers>     <context>       <resource uri="config://spring/objects"/>
      <!--Dao-->       <resource uri="assembly://Order.Dao/Order.Dao.Config/Dao.xml"/>       <!--Service-->       <resource uri="assembly://Order.Service/Order.Service.Config/Service.xml"/>
    </context>     <objects xmlns="http://www.springframework.net"              xmlns:aop="http://www.springframework.net/aop">
      <object id="Order.Host" type="Order.Host.Implement.OrderServer, Order.Host">         <property name="Manager" ref="Order.OrderManager"/>       </object>
    </objects>   </spring>
  <appSettings>     <add key="Spring.Data.NHibernate.Support.SessionScope.SessionFactoryObjectName" value="NHibernateSessionFactory"/>   </appSettings>
  <system.web>     <compilation debug="true" targetFramework="4.0"/>
    <httpModules>       <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>     </httpModules>
  </system.web>   <system.serviceModel>     <services>       <service name="Order.Host">         <endpoint address="" binding="wsHttpBinding" bindingConfiguration="ServerBinding" contract="Order.Host.IOrderContract"/>         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>       </service>     </services>     <bindings>       <wsHttpBinding >         <binding name="ServerBinding" transactionFlow="true"  >         </binding>       </wsHttpBinding>     </bindings>     <behaviors>       <serviceBehaviors>         <behavior>           <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->           <serviceMetadata httpGetEnabled="true"/>           <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->           <serviceDebug includeExceptionDetailInFaults="true"/>         </behavior>       </serviceBehaviors>     </behaviors>     <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>   </system.serviceModel><system.webServer>     <modules runAllManagedModulesForAllRequests="true"/>   </system.webServer>   </configuration>

<%@ ServiceHost Language="C#" Debug="true" Service="Order.Host" Factory="Spring.ServiceModel.Activation.ServiceHostFactory"%>

  四、客户端

HostTest

[TestFixture]     publicclass HostTest     {         private CustomerContractClient customerProxy;
        private OrderContractClient orderProxy;
        [SetUp]         publicvoid Init()         {             customerProxy =new CustomerContractClient();             orderProxy =new OrderContractClient();         }
        [Test]         publicvoid InitData()         {             using (TransactionScope scope =new TransactionScope())             {                 customerProxy.Save(new CustomerInfo                 {                     Name ="刘冬"                 });
                scope.Complete();             }         }
        [Test]         publicvoid DistributedTransactionTest()         {             using (TransactionScope scope =new TransactionScope())             {                 try                 {                     CustomerInfo customer = customerProxy.Get(1);                     orderProxy.Save(new OrderInfo                     {                         Address ="中国北京",                         CustomerId = (int)customer.ID,                         OrderDate = DateTime.Now                     });                     customer.Money +=1000;                     customerProxy.Update(customer);                     scope.Complete();                     Console.WriteLine("分布式事务已提交");                 }                 catch (Exception ex)                 {                     Transaction.Current.Rollback();                     Console.WriteLine("发送错误:分布式事务已回滚");                 }             }         }     }

  

  五、运行效果

  1.初始化数据

  

  2.建立第一张订单,订金小于3000

  

  

  3.建立第一张订单,订金小于3000

  4.建立第一张订单,订金等于3000

  5.建立第一张订单,订金大于3000,事务回滚。

  好了,基于Web Service的分布式事务已经实现了。

  代码下载

  出处:http://www.cnblogs.com/GoodHelper/archive/2010/07/30/SpringNetDistributedTransaction2.html

  欢迎转载,但需保留版权。

posted on 2013-02-23 14:49 Alfa 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/wuyifu/archive/2013/02/23/2923436.html

spring.net nhibernate 分布布式事务(下)相关推荐

  1. 微服务-多线程-队列-设计模式-MySQL-分布式事务

    微服务-多线程-队列-设计模式-MySQL-分布式事务持续更新 周更 什么是微服务,微服务的好处 微服务的几个常用组件 Eurake Hytrix 服务熔断和降级 Ribbon Feign Gatew ...

  2. Seata-分布式事务中间件

    文章目录 Seata-分布式事务中间件 seata简介 1.seata术语 TC (Transaction Coordinator) - 事务协调者 TM (Transaction Manager) ...

  3. Seata----分布式事务框架

    Seata----分布式事务框架 一. Seata简介 二. 什么是分布式事务问题? ①. 单体应用 ②. 微服务应用 三. Seata原理和设计 ①. 定义一个分布式事务 ②. 协议分布式事务处理过 ...

  4. 布式事务实践 解决数据一致性 Spring事务机制

    Spring事务机制 介绍Spring的事务机制.事物抽象.内部事务和外部事物,以及常用的几种事务管理的实现,包括DataSource.JPA.JMS.JTA都通过实例进行说明.还有XA以及两阶段提交 ...

  5. Spring Cloud Alibaba--分布式事务框架Seata

    Seata作用:分布式事务框架Seata用于保证微服务间的事务一致性. Seata中涉及的对象种类:事务管理者TM.资源管理者RM.事务协调者TC. 参考博客:阿里开源的分布式事务框架 Seata

  6. 分布式事务系列02--分布式事务定义,理论基础--CAP,BASE,酸碱平衡

    https://blog.csdn.net/u010425776/article/details/79516298 目录 一.什么是分布式事务? 二.CAP理论 三.BASE理论 酸碱平衡----AC ...

  7. LCN分布式事务学习0-分布式事务理论基础

    1. 事务概述 1.1 事务的定义 将一个活动涉及到的所有操作纳入到一个不可分割的执行单元,只要其中任一操作执行失败,都将导致整个执行单元回滚. 简单地说,事务提供一种"要么什么都不做,要么 ...

  8. seta-分布式事务介绍

    一.前置知识 2.分布式事务 分布式事务指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上,且属于不同的应用,分布式事务需要保证这些操作要么全部成功,要么 ...

  9. 2021-09-16-分布式事务解决方案理解

    文章目录 什么是分布式事务 分布式事务产生的原因 数据库分库分表 应用SOA化--微服务化 分布式事务解决方案 两阶段提交(2PC) 两阶段提交缺点 三阶段提交(3PC) CanCommit阶段 Pr ...

最新文章

  1. github上传文件夹教程
  2. 《Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network》阅读笔记
  3. 结构体、类的成员对齐
  4. web自动化测试---概述
  5. 字典的最大深度 python 实现
  6. Python面向对象的基本实现
  7. bzoj 4131: 并行博弈(博弈)
  8. 蓝彗星(差分+前缀和)
  9. pycharm 变量批量重命名
  10. 计算机网络技术毕业生实习报告_计算机网络毕业实习报告
  11. jquery,Ajax判断验证码是否正确,不正确阻止提交
  12. 分析案例:贷款逾期分析
  13. 交换机 路由器模拟仿真软件命令
  14. AX 2009 删除已经发出领料单的订单行
  15. pwnable.kr passcode
  16. 数据分析大数据面试题大杂烩01
  17. Not creating XLA devices, tf_xla_enable_xla_devices not set 问题
  18. 中国软件行业协会常务副秘书长陈宝国博士带队调研擎天科技
  19. VTK、ITK安装及ITK读取图片、VTK显示示例(CMake)
  20. 竖线分割c语言循环获取数据,用c语言对这样一段话进行解码,每一个竖线是一个分段...

热门文章

  1. Android使用ActionBar和ViewPager切换页面
  2. 有向图——强连通分量
  3. easyNeurons 神经网络入门教程
  4. golang经典书籍--Go语言实战
  5. linux下cd命令
  6. 汇编语言--8086CPU
  7. 以指针的形式和以下标的形式访问指针?以指针的形式和以下标的形式访问数组?
  8. java:lock锁
  9. python五十二:__setattr__,__delattr__,__getattr__方法
  10. tomcat中的几种log catalina localhost