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

2023-09-03 04:53:58 作者:古典大全

说我有一个Windows窗体应用程序,它连接到的 N 的数据库,用的 N 的连接,同时打开。

Say I'm having a Windows Form application which connected to n databases, with n connections opened simultaneously.

我正在寻找的是做所有这些数据库的事务中一气呵成。

What I'm looking for is to do a transaction with all of those databases in one go.

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

For example if I were to have 2 database connections :

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

所有写作是罚款在第一,但事情就当我想在这里和那里,并没有查询到何况可能性增加一个新的连接形式的冗余。

Writing all that is fine at first, but things get kind of redundant when I wanted to query here and there, and not to mention the possibility to adding a new connection.

我想要是循环中的所有已注册的会话,并把它包在一个服务,大概是这样的:

What I wanted is to loop all of the registered session and wrap it up in a service, probably something like this :

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 循环使用,这将意味着,如果连接成功,但连接B不是,那么只有连接B将被回滚

If I were to use using in the foreach loop, it would mean that if connection A successful but connection B wasn't, then only connection B would be rolled back.

推荐答案

看来你可能会重新发明的TransactionScope 。做这一切在工作单位很简单*:

It seems you may be re-inventing TransactionScope. Doing all this under a unit of work is straightforward*:

  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 XA or DTC resource
     scope.Complete(); // If you are happy
  }

的东西在这里并不需要是直列 - 它可以是不同的类,或不同的组件

Stuff here doesn't need to be inline at all - it can be in a different class, or a different assembly.

现在小字:

* 记住你使用一个以上的数据库连接的同时,或不同的连接,或多种技术,这将需要的 2阶段提交并升级为 DTC 交易以以确保酸在整个资源。 DTC本身有很多更小的印刷和带来更多的在企业网络中的挑战,如防火墙,集群,的安全配置和错误的。如果你能打开下一个之前把所有的连接使用相同的数据库和相同的连接字符串的设置,并关闭一个,那么你可避免DTC 。

* Just remember any time you use more than one database connection concurrently, or different connections, or multiple technologies, that this will require 2 phase commit and escalate to a DTC transaction in order to ensure ACID across the resources. DTC itself has lots more small print and poses many more challenges in a corporate network, like firewalls, clustering, security configuration and bugs. If you can keep all your connections using the same database and same connection string settings, and close one before opening the next, then you can avoid DTC.

维护跨多个ACID资源的事务总是会保持锁定在所有这些,直到事务被提交或回滚。

Maintaining a transaction across multiple ACID resources will invariably maintain locks over all of these until the transaction is committed or rolled back.

和最后一点值得一提的是默认的隔离级别的TransactionScope 是序列化的,这是容易出现死锁。你可能想降下来,以Read承诺。

And last point worth mentioning is the default isolation level with TransactionScope is Serializable, which is prone to deadlocks. You'll probably want to drop this down to Read Committed.

如果DO 的东西在多个线程,则需要拉拢的 DependentTransaction

If do Stuff across multiple threads, you'll need to rope in DependentTransaction