浏览到chnking的WCF的分布式事务处理不错,转载过来分享一下。
1、 WCF分布式事务例子
这里也用转账的例子说事。
用户在系统A和系统B都有账户,账户间的资金可以互转,系统A的资金减少多少,系统B的相应账户的资金就增加多少。
系统A机器上有数据库AccountA,系统B机器上有数据库AccountB,数据库的结构一样,都有一个数据表Account,结构如下:
为了演示TxF事务性文件,在系统B中增加了一个写文件的操作,记录本次转账操作的信息。转账的所有操作步骤:系统A上账户上减少金额,系统B上记录转账信息文件,系统B上相应账户资金增加这三个操作都在一个事务流中,要么全部完成,要么全部回滚。
系统A和系统B分别在服务器A和服务器B上。系统A在账户上减少金额后调用系统B的WCF服务,在系统B中继续增加账户资金,生成转账信息文件。
下面开始这个例子的完整过程。
1.1. 建立系统B转账WCF服务
建立服务契约:
[ServiceContract]
public interface IAccountB
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void deposit(int depositorid, double amount);
}
服务契约就一个方法deposit,其中depositorid表示账户id,amount表示要从系统A转账到系统B的金额。
TransactionFlow这个属性指示operation是否跟随调用端的事务流,参数含义:
TransactionFlowOption.NotAllowed:表示此operation不跟随传入的事务流,不参与分布式事务。
TransactionFlowOption.Allowed:表示此opreation可以跟随传入的事务流,如果有传入的事务流则参与,如果没有传入的事务流则不参与,但是可以启动本地的事务。
TransactionFlowOption.Mandatory:表示此operation必须跟随传入的事务,参与分布式事务,如果调用此operation的客户端没有事务流则抛出异常。
下面是服务实现:
1 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 2 3 public class AccountBService : IAccountB 4 5 { 6 7 [OperationBehavior(TransactionScopeRequired = true)] 8 9 public void deposit(int depositorid, double amount) 10 11 { 12 13 #region 新建事务性文件 14 15 string path = @"c:\test.txt"; 16 17 FileStream fs = TransactedFile.Open(path, System.IO.FileMode.Create, 18 19 System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite); 20 21 string fileContent = string.Format("从系统A转账到系统B\r\n用户ID:{0}\r\n转账金额为:{1}", depositorid.ToString(), amount.ToString()); 22 23 byte[] byteArrar = Encoding.UTF8.GetBytes(fileContent); 24 25 fs.Write(byteArrar, 0, byteArrar.Count()); 26 27 fs.Flush(); 28 29 fs.Close(); 30 31 #endregion 32 33 34 35 #region 数据访问,在指定账户上增加存款 36 37 string connstr = ConfigurationManager.ConnectionStrings["ConnStr"].ToString(); 38 39 SqlCommand mySqlCommand = new SqlCommand("update account set amount = amount + @amount where depositorid = @depositorid "); 40 41 mySqlCommand.Connection = new SqlConnection(connstr); 42 43 SqlParameter par1 = new SqlParameter("@amount", SqlDbType.Decimal); 44 45 par1.Value = amount; 46 47 mySqlCommand.Parameters.Add(par1); 48 49 par1 = new SqlParameter("@depositorid", SqlDbType.Int); 50 51 par1.Value = depositorid; 52 53 mySqlCommand.Parameters.Add(par1); 54 55 mySqlCommand.Connection.Open(); 56 57 mySqlCommand.ExecuteNonQuery(); 58 59 mySqlCommand.Connection.Close(); 60 61 #endregion 62 63 } 64 65 }
服务实现了deposit操作。
[OperationBehavior(TransactionScopeRequired = true)],这里的TransactionScopeRequired = true表示这个操作在TransactionScope内执行,加上前面OperationContract上的TransactionFlowOption.Allowed 允许跟随事务的设置,这个deposit的操作将会参与客户端发起的分布式事务。
实现的deposit操作中完成两个任务,先转账信息写入c:\test.txt文件,这里写文件操作使用了TxF事务性文件操作TransactedFile.Open,关于TxF的操作部分的代码微软有提供,在本文中提供的代码中包含了这部分源码。使用事务性文件操作,在事务中的其他事务资源操作失败后,文件操作也会回滚。
1.2. 建立系统A转账客户端
系统A是个Console应用: