【问题标题】:C# controlling a transaction across multiple databasesC# 控制跨多个数据库的事务
【发布时间】:2014-04-26 02:05:03
【问题描述】:

假设我有一个连接到 n 数据库的 Windows 窗体应用程序,同时打开了 n 连接。

我正在寻找的是一次性与所有这些数据库进行交易。

例如,如果我有 2 个数据库连接:

using (ITransaction tx1 = session1.OpenTransaction())
{
    using (ITransaction tx2 = session2.OpenTransaction())
    {
        // Do the query thingy here
    }
}

一开始写一切都很好,但是当我想到处查询时,事情就变得有点多余了,更不用说添加新连接的可能性了。

我想要的是循环所有注册的会话并将其包装在一个服务中,可能是这样的:

class TransactionManager
{
    private ISession[] _sessions;

    public TransactionManager(string[] connectionStrings)
    {
        // Initialize the sessions here
    }

    public function DoTransaction(string query)
    {
        foreach (ISession session in _sessions)
        {
            // What to do here? Using? Try-catch?
        }
    }
}

如果我在 foreach 循环中使用 using,则意味着如果连接 A 成功但连接 B 不成功,则只有连接 B 会回滚。

【问题讨论】:

    标签: c# .net transactionscope


    【解决方案1】:

    看来您可能正在重新发明TransactionScope。在一个工作单元下完成所有这些工作很简单*:

      using (TransactionScope scope = new TransactionScope())
      {
         ... Do Stuff with Connection 1 using SqlDataReader
         ... Do Stuff with Connection 2 using Entity Framework
         ... Do Stuff with Connection 3 on another Oracle Database
         ... And for good measure do some stuff in MSMQ or other DTC resource
         scope.Complete(); // If you are happy
      }
    

    Stuff 根本不需要内联 - 它可以在不同的类或不同的程序集中。无需使用TransactionScope 显式注册数据库或队列连接 - 一切都会发生在automagically,前提是您使用的资源能够enlist into an ambient transaction

    现在是小字:

    • * 任何时候您同时使用多个数据库连接、不同的连接字符串或多种技术,这将需要2 phase commit 并升级到DTC 事务以确保跨资源的ACID。 DTC 本身有更多的小字体和更多的challenges in a corporate network,例如firewallsclusteringsecurity configurationbugs

    • 但是,对于 MS Sql Server 上的轻量级事务,如果您可以使用相同的数据库和相同的数据库来保持所有连接 连接字符串设置,并在打开之前关闭每个连接 下一个,然后你can avoid DTC

    • 跨多个 ACID 资源维护事务将始终保持对这些资源的锁定,直到事务被提交或回滚。在大容量企业中,这通常不会带来良好的邻居关系,因此请务必考虑锁定的后果。

    • 如果Stuff 是跨多个线程完成的,您需要使用DependentTransaction 进行绑定

    • 最后值得一提的是TransactionScope 的默认隔离级别是Serializable,这很容易出现死锁。在大多数非关键场景中,您可能可以将其降至 Read Committed

    【讨论】:

    • 不敢相信我现在才知道 TransactionScope。这段时间我都去哪儿了??
    • 另外,TransactionScope 有一个糟糕的习惯,即升级到 MSDTC 的多个连接,这具有糟糕的性能。厌倦它。
    • 您的* 要点是否也适用于给定的示例,即多个数据库连接完全不同的类型
    • 是的。例如如果所有数据库都进行了相应配置,您将能够跨 SqlServer、Oracle 和 MQSeries 队列执行两阶段事务。当与非 Windows 技术栈通信时(例如与托管在 *nix 服务器上的 Oracle),您可能需要在您的原始 .Net 服务器上配置 XA。但是,您可能希望在使用 ACID 事务损害您的企业之前分析分布式锁定的负面影响。有(诚然复杂的)替代方案,如补偿和 BASE。
    • 我能否确认一下,是否可以在单个 TransactionScope 中使用 2 个 DbContext,它们都连接到不同 SQL Server 上的不同 DB,并且所有操作都是原子的?
    【解决方案2】:

    使用 TransactionScope,它将负责提交或回滚所有包含的事务:

    using (var ts = new TransactionScope())
    {
       ... // your old code
    
       ts.Complete()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-21
      • 2017-12-27
      • 2011-02-10
      • 1970-01-01
      相关资源
      最近更新 更多