2014-03-19 37 views
20

说我具有连接到n数据库Windows窗体应用程序,交易与n连接同时打开。C#控制跨多个数据库

我在找的是一次性处理所有这些数据库。

例如如果我有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会被回滚。

回答

24

看来你可能会重新发明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,如firewalls,clustering,security configurationbugs
  • 但是,如果您可以使用相同的数据库和相同的连接字符串设置保留所有连接,并在打开 之前关闭每个连接,然后您can avoid DTC

  • 在多个ACID资源之间维护事务将始终保持这些资源的锁定,直到事务被提交或回退。这通常不会造成大批量企业的良好睦邻关系,因此请务必考虑锁定的后果。

  • 如果Stuff跨多个线程完成的,你需要拉拢DependentTransaction

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

+2

不能相信我刚刚才知道TransactionScope。我一直都在这个时间? –

+1

此外,'TransactionScope'有一个可怕的习惯,即将多个连接升级到MSDTC,这种连接性能很糟糕。对此感到厌倦。 – Haney

+0

您的'*'项目符号点是否也适用于给定示例,即完全不同类型*的多个数据库连接*? – Timo

4

使用的TransactionScope,这将需要提交或回滚全部纳入交易的护理:

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

    ts.Complete() 
}