web-dev-qa-db-ja.com

複数のデータベースにわたるトランザクションを制御するC#

n接続が同時に開かれたnデータベースに接続するWindowsフォームアプリケーションがあるとします。

私が探しているのは、それらすべてのデータベースとのトランザクションを一度に実行することです。

たとえば、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のみがロールバックされることを意味します。

26
Samuel Adam

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になります。

今、小さな印刷:

  • *複数のデータベース接続、異なる接続文字列、または複数のテクノロジーを同時に使用する場合は常に、ACIDを確保するために 2フェーズコミット が必要で、DTCトランザクションにエスカレートします。リソース全体。 DTC自体はより小さな活字であり、 ファイアウォールクラスタリングセキュリティ構成 と_などのより多くの 企業ネットワークにおける課題 を提起します バグ
  • ただし、MS SQL Serverの軽量トランザクションでは、同じデータベースと同じ接続文字列設定を使用してすべての接続を保持でき、次の接続を開く前に各接続を閉じると、 DTCを回避できる になります。

  • 複数のACIDリソース間でトランザクションを維持すると、トランザクションがコミットまたはロールバックされるまで、これらのリソースのロックが常に維持されます。これは多くの場合、大規模な企業では良好な近さをもたらさないため、ロックの影響を考慮してください。

  • Stuffが複数のスレッドにまたがって行われる場合は、 DependentTransaction にロープを張る必要があります

  • 言及する価値のある最後の点は、TransactionScopeがシリアル化可能であるデフォルトの分離レベルであり、デッドロックが発生しやすいです。ほとんどの重要でないシナリオでは、これを Read Committed にドロップできるでしょう。

38
StuartLC

transactionScopeを使用すると、含まれているすべてのトランザクションをコミットまたはロールバックします。

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

   ts.Complete()
}
6
Zdravko Danev