[WCF编程]12.事务:服务事务编程(下)
一、投票与提交
虽然WCF负责事务传播及两阶段提交协议的管理工作,但是 她不知道事务是否应该提交或终止。这需要根服务告诉WCF应该何时启动两阶段提交协议、是提交还是终止。WCF提供了两种编程模式来对事务的结果进行投票,即声明式和显式模式。
声明式投票
WCF可以代替服务自动完成提交或终止事务的投票。自动投票是通过OpreationBehavior的TransactionAutoComplete属性来控制的。
TransactionAutoComplete属性的默认值为true,可以如下使用:
//服务端代码必须置于服务中执行 [OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete=true)] public void CSMethod() { //获取当前事务对象 Transaction transaction = Transaction.Current; }当这个属性设置为true时,如果操作里没有未处理的异常,则WCF将会自动提交事务。如果存在异常,WCF将会投票终止事务。注意,即使WCF必须通过捕获异常来终止事务,它也是会重新抛出异常,以便异常沿着调用链传播。
为了依赖自动投票,必须把服务的TransactionScopeRequired 属性设置为true,因为自动投票只有在WCF为服务设置了事务环境时才有用。
在TransactionScopeRequired设置为true时,要尽量避免捕获和处理异常,显式避免终止事务。
//服务端代码必须置于服务中执行 [OperationBehavior(TransactionScopeRequired = true)] public void CSMethod() { try { ... } catch { Transactionn.Current.Rollback(); } }虽然服务捕获了一次异常,但操作仍会引发异常,这是因为WCF会在客户端抛出现像AbortedException一样的异常。WCF是会这样做 的,因为服务也许是包含多个服务、机器和站点事务的一部分。
明确投票
当TransactionAutoComplete设置为false时,需要使用明确投票。
当禁止声明式投票时,默认情况下,无论是否发生异常,WCF将会自动终止所有的事务,你需要明确使用操作上下文的SetTransactionComplete()方法来提交事务。
public sealed class OperationContext : IExtensibleObject<OperationContext> { //......</span><span style="color: #008000">//</span><span style="color: #008000"> 摘要: </span><span style="color: #008000">//</span><span style="color: #008000"> 提交当前正在执行的事务。 </span><span style="color: #008000">//</span> <span style="color: #008000">//</span><span style="color: #008000"> 异常: </span><span style="color: #008000">//</span><span style="color: #008000"> System.InvalidOperationException: </span><span style="color: #008000">//</span><span style="color: #008000"> 上下文中没有任何事务。</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> SetTransactionComplete();
}
确保在调用SetTransactionComplete()之后没有再执行任何操作,特别是事务性工作。
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete=false)] public void CSMethod() { try { OperationContext.Current.SetTransactionComplete(); } catch (Exception) { throw; } }如果调用后尝试执行任何事务性工作,即使访问OperationContext.Current,WCF就会抛出相关的异常并终止事务。
明确投票是为投票需要依赖其它信息(包括异常和错误)的情况而设计的。但是,对于大部分应用程序与服务来说,应该选择简单的声明式投票方式。
终止事务
事务何时结束是由事务发起者决定的。根服务可以调用其它服务并把事务传播给它们。注意,下游服务只能使用对事务投票,不能提交完成事务。只有根事务可以同时投票和提交完成事务。
当非事务型客户端发起事务时,事务会在客户销毁事务对象时结束。
二、事务超时
当事务试图访问其它事务占有的资源管理器且需要占用很久时可能会发生死锁。为了解决这个问题,事务必须能够在一定的超时事件(默认60s)内自动终止事务。一旦终止事务,任何传播事务到服务的操作都会导致异常。
超时的服务行为属性,而且服务上的所有终结点的所有操作使用相同的超时事件。可以通过ServiceBehaviorAttribute的TransactionTimeout属性来设置超时时间。
例如,下面设计30s超时的代码:
[ServiceBehavior(TransactionTimeout="00:00:30")] public class ClientServiceTransaction : IClientServiceTransaction {......}也可以在宿主配置文件里通过定义服务的自定义行为来配置事务超时事件。
...... <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceTimeouts transactionTimeout="00:00:30"/> </behavior> </serviceBehaviors> </behaviors> ......以上事务超时的最大值为10min。可以通过机器配置文件来指定超过10分钟的最大值,如40分钟,以下是对machine.config的配置:
...... <system.transactions> <mechineSettings maxTimeout = "00:40:00"/> </system.transactions> ......