zoukankan      html  css  js  c++  java
  • 化零为整WCF(14) 事务(Transaction)


    介绍
    WCF(Windows Communication Foundation) - 事务(Transaction):
        ·对契约方法 使用 TransactionFlowAttribute声明(设置TransactionFlowOption参 数 ),以指定服务操作的事务流策略
        ·对
    服务方法是用OperationBehaviorAttribute 声明(设置TransactionScopeRequired 参数),以指定方法是否在事务范围(TransactionScope )内执行
        ·
    配置host和client的binding节点的transactionFlow 属 性,以指定绑定是否支持流事务


    示例
    1、服务
    Hello.cs

    using  System;
    using  System.Collections.Generic;
    using  System.Linq;
    using  System.Text;

    using  System.ServiceModel;

    namespace  WCF.ServiceLib.Transaction
    {
        
    ///   <summary>
        
    ///  IHello接口
        
    ///   </summary>

        [ServiceContract]
        
    public   interface  IHello
        
    {
            
    ///   <summary>
            
    ///  打招呼方法
            
    ///   </summary>
            
    ///   <param name="name"> 人名 </param>
            
    ///   <remarks>
            
    ///  TransactionFlow - 指定服务操作是否愿意接受来自客户端的传入事 务
            
    ///  NotAllowed - 禁止事务。默认值
            
    ///  Allowed - 允许事务
            
    ///  Mandatory - 强制事务
            
    ///   </remarks>
            
    ///   <returns></returns>

            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Mandatory)]
            
    void  WriteHello( string  name);
        }


        
    ///   <summary>
        
    ///  Hello类
        
    ///   </summary>

         public   class  Hello : IHello
        
    {
            
    ///   <summary>
            
    ///  打招呼方法
            
    ///   </summary>
            
    ///   <param name="name"> 人名 </param>
            
    ///   <remarks>
            
    ///  OperationBehavior - 指定服务方法的本地执行行为
            
    ///  1、TransactionScopeRequired - 如果方法需要事务范围 才能执行,则为 true;否则为 false。默认值为 false
            
    ///  将 TransactionScopeRequired 设置为 true,可以要 求操作在事务范围内执行。如果流事务可用,则操作会在该事务内执行。如果流事务不可用,则会创建一个新事务并使用它来执行操作
            
    ///  2、TransactionAutoComplete - 默认值为 true
            
    ///  true - 当方法完成执行时,将把该事务标志为完成(自动提交事务)
            
    ///  false - 需要调用 OperationContext.Current.SetTransactionComplete()方法来手工配置该事务的正确完成;否则,该事务将 被标志为失败(手动提交事务)
            
    ///   </remarks>
            
    ///   <returns></returns>

            [OperationBehavior(TransactionScopeRequired  =   true , TransactionAutoComplete  =   true )]
            
    public   void  WriteHello( string  name)
            
    {
                DBDataContext ctx 
    =   new  DBDataContext();

                ctx.Items.InsertOnSubmit(
                    
    new  Item
                    
    {
                        Title 
    =   string .Format( " Hello: {0}, TransactionId: {1} " , name, System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier),
                        CreatedTime 
    =  DateTime.Now
                    }
    );

                ctx.SubmitChanges();
            }

        }

    }


    Hi.cs

    using  System;
    using  System.Collections.Generic;
    using  System.Linq;
    using  System.Text;

    using  System.ServiceModel;

    namespace  WCF.ServiceLib.Transaction
    {
        
    ///   <summary>
        
    ///  IHi接口
        
    ///   </summary>

        [ServiceContract]
        
    public   interface  IHi
        
    {
            
    ///   <summary>
            
    ///  打招呼方法
            
    ///   </summary>
            
    ///   <param name="name"> 人名 </param>
            
    ///   <returns></returns>

            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Mandatory)]
            
    void  WriteHi( string  name);
        }


        
    ///   <summary>
        
    ///  Hi类
        
    ///   </summary>

         public   class  Hi : IHi
        
    {
            
    ///   <summary>
            
    ///  打招呼方法
            
    ///   </summary>
            
    ///   <param name="name"> 人名 </param>
            
    ///   <returns></returns>

            [OperationBehavior(TransactionScopeRequired  =   true , TransactionAutoComplete  =   true )]
            
    public   void  WriteHi( string  name)
            
    {
                
    if  (DateTime.Now.Second  %   2   ==   0 )
                    
    throw   new  System.Exception( " 为测试事务而抛出的异常 " );

                DBDataContext ctx 
    =   new  DBDataContext();

                ctx.Items.InsertOnSubmit(
                    
    new  Item
                    
    {
                        Title 
    =   string .Format( " Hi: {0}, TransactionId: {1} " , name, System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier),
                        CreatedTime 
    =  DateTime.Now
                    }
    );

                ctx.SubmitChanges();
            }

        }

    }


    Result.cs

    using  System;
    using  System.Collections.Generic;
    using  System.Linq;
    using  System.Text;

    using  System.ServiceModel;

    namespace  WCF.ServiceLib.Transaction
    {
        
    ///   <summary>
        
    ///  结果接口
        
    ///   </summary>

        [ServiceContract]
        
    public   interface  IResult
        
    {
            [OperationContract]
            List
    < Item >  GetResult();
        }


        
    ///   <summary>
        
    ///  结果类
        
    ///   </summary>

         public   class  Result : IResult
        
    {
            
    ///   <summary>
            
    ///  返回数据库结果
            
    ///   </summary>
            
    ///   <returns></returns>

             public  List < Item >  GetResult()
            
    {
                DBDataContext ctx 
    =   new  DBDataContext();

                var result 
    =  from l  in  ctx.Items
                             orderby l.CreatedTime descending
                             select l;

                
    return  result.ToList();
            }

        }

    }



    2、宿主
    Hello.svc

    <% @ ServiceHost Language = " C# "  Debug = " true "  Service = " WCF.ServiceLib.Transaction.Hello "   %>


    Hi.svc

    <% @ ServiceHost Language = " C# "  Debug = " true "  Service = " WCF.ServiceLib.Transaction.Hi "   %>


    Result.svc

    <% @ ServiceHost Language = " C# "  Debug = " true "  Service = " WCF.ServiceLib.Transaction.Result "   %>


    Web.config

    <? xml version="1.0" ?>
    < configuration >
        
    < system.serviceModel >
            
    < behaviors >
                
    < serviceBehaviors >
                    
    < behavior  name ="TransactionBehavior" >
                        
    <!-- httpGetEnabled - 指 示是否发布服务元数据以便使用 HTTP/GET 请求进行检索,如果发布 WSDL,则为 true,否则为 false,默认值为 false -->
                        
    < serviceMetadata  httpGetEnabled ="true"   />
                        
    < serviceDebug  includeExceptionDetailInFaults ="true" />
                    
    </ behavior >
                
    </ serviceBehaviors >
            
    </ behaviors >
            
    < services >
                
    <!-- name - 提供服务的类名 -->
                
    <!-- behaviorConfiguration - 指定相关的行为配置 -->
                
    < service  name ="WCF.ServiceLib.Transaction.Hello"  behaviorConfiguration ="TransactionBehavior" >
                    
    <!-- address - 服务地址 -->
                    
    <!-- binding - 通信方式 -->
                    
    <!-- contract - 服务契约 -->
                    
    <!-- bindingConfiguration - 指定相关的绑定配置 -->
                    
    < endpoint  address =""  binding ="wsHttpBinding"  contract ="WCF.ServiceLib.Transaction.IHello"  bindingConfiguration ="TransactionConfiguration"   />
                
    </ service >
                
    < service  name ="WCF.ServiceLib.Transaction.Hi"  behaviorConfiguration ="TransactionBehavior" >
                    
    < endpoint  address =""  binding ="wsHttpBinding"  contract ="WCF.ServiceLib.Transaction.IHi"  bindingConfiguration ="TransactionConfiguration"   />
                
    </ service >
                
    < service  name ="WCF.ServiceLib.Transaction.Result"  behaviorConfiguration ="TransactionBehavior" >
                    
    < endpoint  address =""  binding ="basicHttpBinding"  contract ="WCF.ServiceLib.Transaction.IResult"   />
                
    </ service >
            
    </ services >
            
    < bindings >
                
    < wsHttpBinding >
                    
    <!-- transactionFlow - 指定该绑定是否应支持流事务 -->
                    
    < binding  name ="TransactionConfiguration"  transactionFlow ="true"   />
                
    </ wsHttpBinding >
            
    </ bindings >
        
    </ system.serviceModel >
    </ configuration >



    3、客户端
    Sample.aspx

    <% @ Page Language = " C# "  MasterPageFile = " ~/Site.master "  AutoEventWireup = " true "  CodeFile = " Sample.aspx.cs "
        Inherits
    = " Transaction_Sample "  Title = " 事务 (Transaction) "  
    %>

    < asp:Content  ID ="Content1"  ContentPlaceHolderID ="head"  runat ="Server" >
    </ asp:Content >
    < asp:Content  ID ="Content2"  ContentPlaceHolderID ="ContentPlaceHolder1"  runat ="Server" >
        
    < p >
            
    < asp:Label  ID ="lblErr"  runat ="server"  ForeColor ="Red"   />
        
    </ p >
        
    < p >
            
    < asp:Button  ID ="btnSubmit"  runat ="server"  Text ="事务测试"  OnClick ="btnSubmit_Click"   />
            
    < br  />
            
    < br  />
            
    < asp:GridView  ID ="GridView1"  runat ="server" >
            
    </ asp:GridView >
        
    </ p >
        
    < p >
            2PC(Two Phase Commitment Protocol)两阶段提交协议(WCF的事务的实现基 于此协议)
            
    < br  />
            实现分布式事务的关键就是两阶段提交协议。在此协议中,一个或多个资源管理器的活动均由一个称为事务协调器的单 独软件组件来控制。此协议中的五个步骤如下:
            
    < br  />
            1、应用程序调用事务协调器中的提交方法。
            
    < br  />
            2、事务协调器将联络事务中涉及的每个资源管理器,并通知它们准备提交事务(这是第一阶段的开始)。
            
    < br  />
            3、为 了以肯定的方式响应准备阶段,资源管理器必须将自己置于以下状态:确保能在被要求提交事务时提交事务, 或在被要求回滚事务时回滚事务。大多数资源管理器会将包含其计划更改的日记文件(或等效文件)写入持久存储区中。如果资源管理器无法准备事务,它会以一个 否定响应来回应事务协调器。
            
    < br  />
            4、事务协调器收集来自资源管理器的所有响应。
            
    < br  />
            5、在 第二阶段,事务协调器将事务的结果通知给每个资源管理器。如果任一资源管理器做出否定响应,则事务协调 器会将一个回滚命令发送给事务中涉及的所有资源管理 器。如果资源管理器都做出肯定响应,则事务协调器会指示所有的资源管理器提交事务。一旦通知资源管理 器提交,此后的事务就不能失败了。通过以肯定的方式响应第一阶段,每个资源管理器均已确保,如果以后通知它提交事务,则事务不会失败。
        
    </ p >
    </ asp:Content >


    Sample.aspx.cs

    using  System;
    using  System.Collections;
    using  System.Configuration;
    using  System.Data;
    using  System.Linq;
    using  System.Web;
    using  System.Web.Security;
    using  System.Web.UI;
    using  System.Web.UI.HtmlControls;
    using  System.Web.UI.WebControls;
    using  System.Web.UI.WebControls.WebParts;
    using  System.Xml.Linq;

    using  System.Threading;

    public   partial   class  Transaction_Sample : System.Web.UI.Page
    {
        
    protected   void  Page_Load( object  sender, EventArgs e)
        
    {

        }


        
    protected   void  btnSubmit_Click( object  sender, EventArgs e)
        
    {
            var proxyHello 
    =   new  TransactionSvc.Hello.HelloClient();
            var proxyHi 
    =   new  TransactionSvc.Hi.HiClient();
            var proxyResult 
    =   new  TransactionSvc.Result.ResultClient();

            System.Transactions.TransactionOptions to 
    =   new  System.Transactions.TransactionOptions();
            
    //  设置事务的超时时间
            to.Timeout  =   new  TimeSpan( 0 0 30 );
            
    //  设置事务的隔离级别
            to.IsolationLevel  =  System.Transactions.IsolationLevel.Serializable;

            
    using  (var ts  =   new  System.Transactions.TransactionScope())
            
    {
                
    try
                
    {
                    proxyHello.WriteHello(
    " webabcd " );
                    proxyHello.Close();

                    proxyHi.WriteHi(
    " webabcd " );
                    proxyHi.Close();

                    ts.Complete();

                    lblErr.Text 
    =   " OK " ;
                }

                
    catch  (Exception ex)
                
    {
                    lblErr.Text 
    =  ex.ToString();
                }

            }


            GridView1.DataSource 
    =  proxyResult.GetResult();
            GridView1.DataBind();
            proxyHello.Close();
        }

    }


    Web.config

    <? xml version="1.0" ?>
    < configuration >
        
    < system.serviceModel >
            
    < client >
                
    <!-- address - 服务地址 -->
                
    <!-- binding - 通信方式 -->
                
    <!-- contract - 服务契约 -->
                
    < endpoint  address ="http://localhost:3502/ServiceHost/Transaction/Hello.svc"  binding ="wsHttpBinding"  contract ="TransactionSvc.Hello.IHello"  bindingConfiguration ="TransactionBindingConfiguration"   />
                
    < endpoint  address ="http://localhost:3502/ServiceHost/Transaction/Hi.svc"  binding ="wsHttpBinding"  contract ="TransactionSvc.Hi.IHi"  bindingConfiguration ="TransactionBindingConfiguration"   />
                
    < endpoint  address ="http://localhost:3502/ServiceHost/Transaction/Result.svc"  binding ="basicHttpBinding"  contract ="TransactionSvc.Result.IResult"   />
            
    </ client >
            
    < bindings >
                
    < wsHttpBinding >
                    
    <!-- transactionFlow - 指定该绑定是否应支持流事务 -->
                    
    < binding  name ="TransactionBindingConfiguration"  transactionFlow ="true"   />
                
    </ wsHttpBinding >
            
    </ bindings >
        
    </ system.serviceModel >
    </ configuration >



    运行结果:
    单击"btnSubmit " 按钮后,可以发现,两个数据库插入操作,要么都执行,要么都不执行

    作者:Angelo Lee
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    c3p0用c3p0-config.xml方式配置 和 用spring配置时一点小区别
    mysql配置
    tomcat监控工具Probe
    tomcat配置
    jsp页面动态包含和静态包含
    servlet3的文件上传
    System.currentTimeMillis()和new Date().getTime()比较
    js-html2canvas导出html图片 导出pdf
    html中使用富文本编辑器
    Vue----vue-resource
  • 原文地址:https://www.cnblogs.com/yefengmeander/p/2887776.html
Copyright © 2011-2022 走看看