You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:29:21