操作行为 之 事务

事务场景:

1. 长期事务:多步骤业务处理,时间跨度长,如几分钟、几天、上月,涉及多个组织或工作流;

2. 短期事务:简单业务处理,时间段,几秒内完成,外部以来很少;

短期事务ACID特性 :原子性、一致性、隔离性、持久性

WCF支持短期事务,利用两种架构来实现:

1. .Net Framewok 和 Windows Infrastructure 支持 Microsoft环境中运行的事务;

2. 利用跨平台的WS-* 标准。

事务化操作

声明操作行为: [OperationBehavior(TransactionScopeRequired=true)],表示将服务操作标识为事务化操作。

操作说明:

1. WCF在将控制权转换为服务方法前创建一个新事务;

2. 将执行线程纳入第一步创建的事务中;

可以显式或隐式的指定当操作完成时的提交事务的操作。 声明操作行为:[OperationBehavior(TransactionAutoComplete=true)]

TransactionAutoCompleted=true 表示若没有抛出任何错误,操作会隐式的认定执行完成;若抛出错误,操作会认定为未完成,针对事务资源的部分更新会被回滚。

TransactionAutoCompleted=false 表示必须在方法返回前显示的调用 OperationContext.Current.SetTransactionCompleted() ,若使用了显式方法,则必须在通信信道中使用基于会话的绑定,并使用[ServiceContract(SessionMode=SessionMode.Allowed)]使用服务契约支持会话。

代码示例:BankService 实现两个方法,GetBalance 不需要事务,Transfer 指定了事务,并隐式提交事务。通过输出事务的 LocalIdentifier和DistributedIdentifier来判断事务执行情况

    public class BankService: IBankService
    {
        #region IBankService Members

        [OperationBehavior(TransactionScopeRequired = false)]
        public double GetBalance(string AccountName)
        {
            DBAccess dbAccess = new DBAccess();
            double amount = dbAccess.GetBalance(AccountName);
            dbAccess.Audit(AccountName, "Query", amount);
            return amount;
        }
        
        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        public void Transfer(string From, string To, double amount)
        {
            try
            {
                Withdraw(From, amount);
                Deposit(To, amount);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        private void Withdraw(string accountName, double amount)
        {
            DBAccess dbAccess = new DBAccess();
            dbAccess.Withdraw(accountName, amount);
            dbAccess.Audit(accountName, "Withdraw", amount);
        }

        private void Deposit(string accountName, double amount)
        {
            DBAccess dbAccess = new DBAccess();
            dbAccess.Deposit(accountName, amount);
            dbAccess.Audit(accountName, "Deposit", amount);
        }
    }

执行结果:

在执行过程中若本机没有打开MSDTC服务,则会出现错误,必须要进行配置。

MSDTC

分布式事务

结果分析:

1. Withdraw 执行中打开第一个数据库连接,当前存在一个上下文事务,并且属于本地事务;

2. Deposit 执行中打开第二个数据库连接,导致事务从本地事务升级到分布式事务;

导致事务升级的代码:

 private void Withdraw(string accountName, double amount)
        {
            DBAccess dbAccess = new DBAccess();//创建SqlConnection
            dbAccess.Withdraw(accountName, amount);
            dbAccess.Audit(accountName, "Withdraw", amount);
        }

        private void Deposit(string accountName, double amount)
        {
            DBAccess dbAccess = new DBAccess();//创建SqlConnection
            dbAccess.Deposit(accountName, amount);
            dbAccess.Audit(accountName, "Deposit", amount);
        }

由于创建两个SqlConnection实例,导致分布式事务出现,可以对此进行优化,将dbAccess 实例作为全局变量,共用同一个SqlConnection实例。优化后结果如下:

本地事务

操作之间的事务流转

背景:跨越服务边界的事务,如:用户下订单需要同时调用订单服务及客户信息服务,增加订单的同时增加客户信息。

在WCF中,服务边界之间的事务流转信息统称为事务流(transaction flow),要在服务边界之间定义事务流,需要以下5个操作:

1. (服务契约)SessionMode.Required,服务契约必须使用Session,只有这样客户端才能在参与事务的各个服务之间共享信息;

2. (操作行为)TransactionScopeRequired=true,操作行为必须在事务上下文内,若不存在上下文,则创建一个新事物;

3. (操作契约)TransactionFlowOption.Allowed,操作契约必须允许消息头中包含用于流转的事务信息;

4. (绑定)TransactionFlow=true,允许事务跨越多个服务调用, 绑定必须激活事务流,使得信道能在SOAP头中放置事务信息,绑定必须支持会话;

5. (客户端)TransactionScope,初始化事务的角色(通常是客户端)必须在调用服务操作时使用一个事务作用域,必须调用TransactionScope.Close()来提交修改;

暂无Demo

posted @ 2011-10-17 21:53  JerryShi  阅读(426)  评论(0编辑  收藏  举报