摘自: 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。

 

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




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

  一、启动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.初始化数据

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




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

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




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

 

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

 

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




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

 

  

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

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




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

 

 

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

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




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

 

 

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

 

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




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

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




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

 

 

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

 

  代码下载

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

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

  

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

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

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

 

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




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

  一、启动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.初始化数据

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




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

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




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

 

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

 

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




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

 

  

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

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




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

 

 

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

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




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

 

 

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

 

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




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

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




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

 

 

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

 

  代码下载

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

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

相关文章: