标签:
在说分布式事务之前,首先了解一下什么是事务。
事务有四个特性:ACID
A是Atomicity,原子性。一个事务往往涉及到许多的子操作,原子性则保证这些子操作要么都做,要么都不做,而不至于出现事务的部分操作成功,而另外一部分操作没有成功。如果事务在执行的过程中发生错误,那么数据库将回滚到事务发生之前的状态。比如银行的转账服务,这个事务的最终结果一定是:某个账户的余额增加了x,而另外一个账户的余额减少了x,或者两个账户的余额未发生变化。而不会出现其他情况。
C是Consistency,一致性。一致性是指事务发生前后,都不会破坏数据库的约束关系,保证了数据库元素的正确性、有效性和完整性。这种约束关系可以是数据库内部的约束,比如数据库元素的值必须在一定的范围内,也可以是应用带来的约束,比如转账以后银行账户的余额不能为负数。
I是Isolation,隔离性。一个事务的操作在未提交以前,是不会被并行发生的其他事务访问到的。也就是说,数据库操作不会看到某个事务的中间操作结果,比如转账过程中,用户是不能查询到一个账户余额减少了,而另外一个账户余额未发生变化的情况。
D是Durability,持久性。事务完成以后,它对数据库的影响是永久性的,即使在数据库系统发生宕机或者其他故障的情况下,这种影响也会得到保持。
简单的来说事务,事务是执行的最小单元。
比如执行的sql语句:delete from Table where FiledsA=‘a‘
这一条sql语句就是一个 事务单元。即最小的执行颗粒。
如果执行两条sql语句:
insert into Table values(‘1‘,‘zc‘)
insert into Table values(‘1‘,‘zc‘)— 与第一条主键冲突
执行如上,包含两个执行单元。这两个执行单元全部执行成功,才算完成任务,则这两个执行单元组成了一个新的事务。
正是因为有这种情况出现,才引出了事务的概念。
对于上述的表述,两个执行单元都在同一个数据库服务器。即在 同一个数据库中操作两次。
那么,如果两个执行单元,分别在不同的数据库呢?
比如说,跨行转账的例子。从银行A转账到银行B。这一个完整的操作,需要各自更改的数据库。
即,银行A中账户余额减少,银行B中账户余额增加。
对于这种不再同一个数据库服务器上的 操作。如果要把这两个执行单元,当成一个事务进行处理。
则需要引入分布式事务的概念。
分布式事务:为了解决不同数据库服务器、分布式系统间的事务问题。
一下是一个实例,现在有两个服务:
服务A:对数据库A进行增删改的操作
服务B:对数据库B进行增删改的操作
现在主要说一下,WCF是如何支持分布式事务的。
WCF 集合了几乎由.NET Framework 所提供的通信方法。
EF中的SaveChanges方法,封装了本地事务。即:执行SaveChanges方法,才会将对实体的更改更新到数据库。
既然要把WCF中的服务做成 支持分布式的形式。所以就要选择一个WCF的通信绑定协议。这样客户端与服务端的通信才可以形成事务。
WCF中的绑定协议:
其中WsHttpBinding协议,在MSDN上的解释:
当然WCF中也可以使用<CustomeBinding>协议,这是一个自定义的绑定协议。有兴趣的可以查一下。
分布式事务实现流程图:
没有分布式事务的情况下,如图:
带红框的是一个事务颗粒。但是根据业务要求,WcfService1和WcfService2需要合并成一个事务。所以需要加上分布式事务。
使用分布式事务的情况,如图:
分布式事务的配置:
服务端webconfig:
<system.serviceModel> <bindings> <wsHttpBinding> <!--使用WsHttpbinding协议--> <!--启动事务流--> <binding name="WsHttpBinding_Default" transactionFlow="true" /> </wsHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="Basic"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <!--service的name是服务端的实现类--> <service name="BasicService.BasicService" behaviorConfiguration="Basic"> <endpoint address ="" binding="wsHttpBinding" bindingConfiguration="WsHttpBinding_Default" contract="BasicContracts.IBasicService" /><!--contract是服务端的契约(接口) 命名空间+类名--> </service> </services> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="1" /> </system.serviceModel>
客户端webconfig:
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="WsHttpBinding_Default" transactionFlow="true" /> </wsHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> <client> <!--考试服务终结点--> <endpoint address="http://192.168.24.146:8111/ExamService.svc?wsdl" binding="wsHttpBinding" bindingConfiguration="WsHttpBinding_Default" contract="ExamContracts.IExamService" name="WsHttpBinding_Services" /> <!--基础服务终结点--> <endpoint address="http://192.168.24.146:8222/BasicService.svc?wsdl" binding="wsHttpBinding" bindingConfiguration="WsHttpBinding_Default" contract="BasicContracts.IBasicService" name="WsHttpBinding_Services" /> </client> </system.serviceModel>
以上是客户端与服务器端的配置文件。
对于服务端的方法,如果要求 服务器端的某个方法,自己可以被其他的事务包含。则需要对这种方法上面加上一个特性。
//契约类(接口)特性 [ServiceContract(SessionMode = SessionMode.Required)] public partial interface IBasic { [OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] void AddBasic(T_Student en); } //实现类特性 public partial class BasicService:IBasic { [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void AddBasic(T_Student en) { DBBasic dbContext = new DBBasic(); T_Student enTemp = new T_Student(); enTemp.StudentId = en.StudentId; enTemp.Sex = en.Sex; enTemp.College = en.College; enTemp.Age = en.Age; dbContext.T_Student.Add(enTemp); dbContext.SaveChanges(); //真正的保存到数据库 } }
在契约类上面的特性,TransactionFlowOption有多个属性可以选择。
TransactionFlowAttribute 只能用于服务方法(Operation/Method)上,它允许我们进行不同的事务参与设置。有一点要注意,我们不能为 IsOneWay=true 的服务设置事务支持。
TransactionFlowOption.NotAllowed: 不参与任何事务。(默认值)
TransactionFlowOption.Allowed: 允许参与事务。也就是说,如果调用方(客户端)和服务Binding启用了事务,则参与。
TransactionFlowOption.Mandatory: 强制启用事务。调用方(客户端)和服务 Binding 必须启用事务才能调用本服务。
客户端,在组合 两个 事务的时候,需要:
using (TransactionScope trans = new TransactionScope()) { //获取考试服务 IExam examService = ExamServiceFactory.GetExam(); //获取基础服务 IBasic basicService = BasicServiceFactory.GetStudent(); //添加考试(正确) T_Exam enExam = new T_Exam(); enExam.ExamId = "1"; enExam.ExamRoom = "501"; enExam.StudentId = "11040342031"; examService.addExam(enExam); ////添加基础(正确) //T_Student enStudent = new T_Student(); //enStudent.StudentId = "11040342031"; //enStudent.Age = "22"; //enStudent.College = "师范学院"; //enStudent.Sex = "男"; //basicService.AddBasic(enStudent); //提交 trans.Complete(); }
这两个 分别具有事务性质的颗粒,通过以上就可以组合成一个新的事务。
使用Wshttpbinding通讯方式之后,WCF中的方法 就可以被其他的事务包进去。
事务,就是由一个个小颗粒组成。事务,也可以由若干个事务组成。
分布式事务,也就是整合一些分别在不同机器上的事务。除了给其他服务提供的事务 加个 特性之外,其他的也都和传统事务相同了。
Demo下载链接:http://download.csdn.net/detail/zc474235918/8505775
标签:
原文地址:http://blog.csdn.net/zc474235918/article/details/44307431