分布式事务处理

概述

 事务是一个最小的工作单元,不论成功与否都作为一个整体进行工作。   
 由于事务是由几个任务组成的,因此如果一个事务作为一个整体是成功的,则事务中的每个任务都必须成功。如果事务中有一部分失败,则整体事务失败。 当事务失败时,系统返回到事务开始前的状态。这个取消所有变化的过程称为“回滚”( rollback )。
 例如,如果一个事务成功更新了两个表,在更新第三个表时失败,则系统将两次更新恢复原状,并返回到原始的状态。

理解事务特性
 一个纯粹的事务包含4个特性
◦ Atomic(原子性) 不可分割性
◦ Consistent(一致性) 事务的结果和预期应该是一样的
◦ Isolated(隔离性) 事务是私有的,对其他事务是不可见的。
◦ Durable(持久性) 一旦事务提交成功,数据的修改时永久的。

[TransactionFlow] Attribute
 [TransactionFlow]是提定服务操作可以接收事务的模式,该Attribute只有一个特性用来标记服务操作的方法。即:TransactionFlowOption
◦ TransactionFlowOption是一个枚举型,包括三个枚举项
 NotAllowed:不允许事务,是缺省值;
 Allowed:允许事务,意味着事务可有可无;
 Mandatory:强制事务,表示事务是必须的。

[TransactionFlow(TransactionFlowOption.Mandatory)]
int serviceMethod(int value)
{

}

[ServiceBehavior]事务属性3-1
TransactionAutoCompleteOnSessionClose
如果想要确保关闭会话后待处理的消息仍然可以完成,应该使用该属性。根据其属性值,事务将会在会话关闭后提交或回滚。
[ServiceBehavior]事务属性3-2

TransactionIsolationLevel
用于指示事务隔离级别。
IsolationLevel枚举如下:
ReadUncommitted : 未提交读
ReadCommitted :已提交读
RepeatableRead :可重复读
Serializable :可序列化
ReadUncommitted是最低的隔离级别
Serializable是最高的隔离级别

[ServiceBehavior]事务属性3-3
TransactionTimeout
用于指示事务的超时时间,默认为TimeSpan.Zero,表示不会受超时时间的限制

[ServiceBehavior(TransactionAutoCompleteOnSessionClose=true,TransactionIsolationLevel=IsolationLevel.ReadCommitted,TransactionTimeout="00:00:30")]
public Class ServiceClass:IServiceClass
{
}

理解事务隔离级别2-1
 脏读:一个事务会读进还没有被另一个事务提交的数据,所以你会看到一些最后被另一个事务回滚掉的数据。
 非可重复性读取:一个事务读进一条记录,另一个事务更改了这条记录并提交完毕,这时候第一个事务再次读这条记录时,它已经改变了。
 幻像读:一个事务用Where子句来检索一个表的数据,另一个事务插入一条新的记录,并且符合Where条件,这样,第一个事务用同一个where条件来检索数据后,就会多出一条记录。

理解事务隔离级别2-2

ReadUncommitted:读取未提交数据,该方式在读取数据时保持共享锁定以避免读取已修改的数据,但在事务结束前可以更改这些数据,这导致非可重复读取或幻读。
ReadCommitted:读取提交数据, 发出共享锁定并允许非独占方式的锁定。该方式与读取未提交数据相相似,这种方式看似和读取未提交数据相似,但有一个区别,事务的只读锁在移到下一行的时候,会解锁,而写入锁却只有在事务完成或者被中止后才解锁,事务要等待所有写入锁解锁。
RepeatableRead:可重复性读取,与读取提交数据相似,在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。防止非可重复读取,但幻读行仍有可能发生。该方式是只读锁也要等到事务结束或者中止才解除

示例:
 Client/Service transaction,最常见的一种事务模型,通常由客户端或服务本身启用一个事务。
设置步骤:
◦ (1) 选择一个支持事务的Binding,设置 TransactionFlow = true。
◦ (2) 设置 TransactionFlow(TransactionFlowOption.Allowed)。
◦ (3) 设置 OperationBehavior(TransactionScopeRequired=true)。

做一个银行转帐的例子:

1, 先创建一个数据表 Account 两个字段 ID balance
2, 创建wcf服务库
接口:

 [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Mandatory)]
        void outMoney(int money);

        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Mandatory)]
        void intoMoney(int money);
}

实现:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,ReleaseServiceInstanceOnTransactionComplete=false)]
    public class Service1 : IService1
    {
        [OperationBehavior(TransactionScopeRequired=true)]
        public void outMoney(int money)  //转出
        {
            using (SqlConnection conn = new SqlConnection("server=.;uid=sa;pwd=123;database=master"))
            {
                SqlCommand cmd = new SqlCommand("",conn);
                conn.Open();
                //得到余额
                cmd.CommandText = "select balance from Account where id='A'";
                decimal m = (decimal)cmd.ExecuteScalar();
                if (m >= money)
                {
                    string sql = "update Account set balance=balance-" + money + " where ID='A'";
                    cmd.CommandText = sql;
                    cmd.ExecuteNonQuery();
                }
                else
                {
                    throw new FaultException("余额不足,转帐失败!");
                }
                conn.Close();
            }
        }

        [OperationBehavior(TransactionScopeRequired = true)]
        public void intoMoney(int money)  //转入
        {
            using (SqlConnection conn = new SqlConnection("server=.;uid=sa;pwd=123;database=master"))
            {
                string sql = "update Account set balance=balance+" + money + " where ID='B'";
                SqlCommand cmd = new SqlCommand(sql, conn);
                conn.Open();
                cmd.ExecuteNonQuery();
                conn.Close();
            }
            //throw new FaultException("发生人为故障,转帐失败!");
        }
}

同时配置文件需要添加绑定,允许事务流

<bindings>
      <wsHttpBinding>
        <binding name="wshttpbind_transaction" transactionFlow="true"></binding>
      </wsHttpBinding>
</bindings>

Endpoint中binbingConfiguration与上面绑定的名字 创建服务端窗体程序,添加相应引用,可启动服务。

      //开启服务
        ServiceHost host = null;
        private void button1_Click(object sender, EventArgs e)
        {
            WSDualHttpBinding bind = new WSDualHttpBinding();
            bind.TransactionFlow = true;
            Uri address = new Uri("http://localhost:3200/bank");
            host = new ServiceHost(typeof(WcfServiceLibrary1.Service1), address);
            host.AddServiceEndpoint(typeof(WcfServiceLibrary1.IService1), bind, "");
            host.Open();
            label1.Text = "服务已启动!";
        }

4, 创建客户端程序,进行转账操作

  //转帐
        private void button1_Click(object sender, EventArgs e)
        {
            WSDualHttpBinding bind = new WSDualHttpBinding();
            bind.TransactionFlow = true;
            bind.ClientBaseAddress = new Uri("http://localhost:5100/");

            EndpointAddress address = new EndpointAddress("http://localhost:3200/bank");
            ChannelFactory<WcfServiceLibrary1.IService1> factory = new ChannelFactory<WcfServiceLibrary1.IService1>(bind, address);
            WcfServiceLibrary1.IService1 client = factory.CreateChannel();

            int m = int.Parse(textBox1.Text);
            using(System.Transactions.TransactionScope tx = new System.Transactions.TransactionScope())
            {
                try
                {
                    client.outMoney(m);
                    client.intoMoney(m);
                    tx.Complete();//提交成功
                    MessageBox.Show("转帐成功!");
                }
                catch(FaultException fe)
                {
                    MessageBox.Show(fe.Message);
                    System.Transactions.Transaction.Current.Rollback();//回滚
                }
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值