C#控制跨多个数据库的事务

时间:2014-03-19 16:37:08

标签: c# .net transactionscope

说我有一个连接到 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循环中使用,则意味着如果连接A成功但连接B不是,那么只会回滚连接B.

2 个答案:

答案 0 :(得分:33)

看来你可能正在重新发明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

答案 1 :(得分:5)

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

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

   ts.Complete()
}