如何基于WCF实现SQL与Couchbase跨服务事务回滚?
如何通过WCF服务实现SQL与Couchbase数据库更新的事务回滚?
当需要让操作SQL和Couchbase的两个服务实现跨库事务回滚时,WCF的事务流机制结合System.Transactions组件可以帮我们达成一致性要求。下面是完整的配置与代码实现细节:
一、配置文件设置
1. Web.config(服务端配置)
服务端核心是开启事务流转、配置支持事务的绑定,同时设置服务行为:
<system.serviceModel> <diagnostics> <messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true" /> </diagnostics> <behaviors> <serviceBehaviors> <behavior name="TransactionBehavior"> <!-- 部署前建议关闭元数据暴露,避免信息泄露 --> <serviceMetadata httpGetEnabled="True" /> <!-- 调试阶段开启异常细节,部署前务必关闭 --> <serviceDebug includeExceptionDetailInFaults="True" /> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="ImpersonationBehavior"> <clientCredentials> <windows allowedImpersonationLevel="Impersonation" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <bindings> <wsHttpBinding> <binding name="wsHttpTransactionBinding" receiveTimeout="00:20:00" sendTimeout="00:20:00" bypassProxyOnLocal="false" transactionFlow="true" maxReceivedMessageSize="2147483647" messageEncoding="Mtom"> <security mode="None" /> </binding> </wsHttpBinding> </bindings> <services> <service behaviorConfiguration="TransactionBehavior" name="BankingService.AccountService"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpTransactionBinding" name="wsHttpEndPoint" contract="SharedLib.IAccountService" /> </service> </services> <!-- 修复服务激活时的内存不足问题 --> <serviceHostingEnvironment minFreeMemoryPercentageToActivateService="1" multipleSiteBindingsEnabled="true"> <serviceActivations> <add relativeAddress="AccountService.svc" service="BankingService.AccountService" factory="WebApp.UnityServiceHostFactory, WebApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </serviceActivations> </serviceHostingEnvironment> <client> <endpoint address="http://localhost:9003/AccountService.svc" behaviorConfiguration="ImpersonationBehavior" binding="wsHttpBinding" bindingConfiguration="wsHttpTransactionBinding" contract="SharedLib.IAccountService" name="wsHttpEndPoint" /> </client> </system.serviceModel>
关键配置点:
wsHttpBinding中设置transactionFlow="true",允许事务上下文在服务间传递- 服务行为里的调试配置仅适合开发阶段,部署前需调整
2. App.config(客户端配置)
客户端需要匹配服务端的绑定规则,确保事务能正常流转:
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="wsHttpTransactionBinding" transactionFlow="true" openTimeout="00:10:00" useDefaultWebProxy="true" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" receiveTimeout="00:20:00" sendTimeout="00:20:00" maxReceivedMessageSize="2147483647" messageEncoding="Mtom"> <security mode="None"> </security> </binding> </wsHttpBinding> <netTcpBinding> <binding name="netTcpTransactionBinding" transactionFlow="true" sendTimeout="00:20:00" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="Transport"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> </security> </binding> </netTcpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="ImpersonationBehavior"> <clientCredentials> <windows allowedImpersonationLevel="Impersonation" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint address="http://localhost:9003/AccountService.svc" behaviorConfiguration="ImpersonationBehavior" binding="wsHttpBinding" bindingConfiguration="wsHttpTransactionBinding" contract="SharedLib.IAccountService" name="wsHttpEndPoint" /> </client> </system.serviceModel>
关键配置点:
- 同样开启
transactionFlow="true",确保客户端发起的事务能传递到服务端 - 额外配置了
netTcpBinding,适合内网环境下更高效的服务调用
二、服务契约定义
在契约中,为需要参与事务的操作标记TransactionFlow属性,明确允许事务上下文流转:
[ServiceContract] public interface IAccountService { [OperationContract] Task<IEnumerable<Account>> GetAccounts(); [OperationContract, TransactionFlow(TransactionFlowOption.Allowed)] Task<bool> Debit(int accountID, int amount); [OperationContract, TransactionFlow(TransactionFlowOption.Allowed)] Task<bool> Credit(int accountID, int amount); [OperationContract] Task<int> GetBalance(int accountID); [OperationContract] Task<MiniStatement> GetMiniStatement(int accountID); }
关键说明:
TransactionFlowOption.Allowed表示该操作可以接受客户端传递的事务上下文- 查询类操作无需参与事务,因此不需要添加该属性
三、服务实现
服务实现类通过ServiceBehavior配置事务隔离级别,同时用TransactionScope包裹跨库操作,确保SQL和Couchbase的操作在同一事务中:
[ServiceBehavior( TransactionIsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, ConcurrencyMode = ConcurrencyMode.Multiple)] public class AccountService : IAccountService { public async Task<IEnumerable<Account>> GetAccounts() { // 查询逻辑,无需事务 // ... } public async Task<bool> Debit(int accountID, int amount) { using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { try { // 1. 更新SQL数据库的账户余额 await UpdateSqlAccountBalance(accountID, -amount); // 2. 更新Couchbase数据库的账户缓存 await UpdateCouchbaseAccountBalance(accountID, -amount); scope.Complete(); return true; } catch (Exception ex) { // 发生异常时,事务自动回滚,两个库的操作都不会生效 return false; } } } public async Task<bool> Credit(int accountID, int amount) { using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { try { // 1. 更新SQL数据库的账户余额 await UpdateSqlAccountBalance(accountID, amount); // 2. 更新Couchbase数据库的账户缓存 await UpdateCouchbaseAccountBalance(accountID, amount); scope.Complete(); return true; } catch (Exception ex) { return false; } } } // 辅助方法实现 private async Task UpdateSqlAccountBalance(int accountID, int amount) { // SQL更新逻辑,可使用ADO.NET或EF Core实现 // ... } private async Task UpdateCouchbaseAccountBalance(int accountID, int amount) { // Couchbase更新逻辑,使用官方.NET SDK实现 // ... } // 其他方法实现... }
关键实现要点:
ServiceBehavior中设置TransactionIsolationLevel为ReadCommitted,这是常用的隔离级别,避免脏读问题TransactionScope启用TransactionScopeAsyncFlowOption.Enabled以支持异步操作- 只有调用
scope.Complete()后事务才会提交,任何异常都会触发自动回滚,保证两个数据库的操作一致性
额外注意事项
- 确保SQL Server和Couchbase都支持分布式事务:SQL Server默认支持,Couchbase建议使用7.0+版本以获得完整事务支持
- 客户端调用时,也可通过
TransactionScope发起事务,让多个服务操作参与到同一事务中 - 部署前记得关闭
serviceDebug includeExceptionDetailInFaults="True"和serviceMetadata httpGetEnabled="True",避免敏感信息泄露
内容的提问来源于stack exchange,提问作者Subasish
相关产品推荐
相关产品推荐

