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のみがロールバックされることを意味します。
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 にドロップできるでしょう。
transactionScopeを使用すると、含まれているすべてのトランザクションをコミットまたはロールバックします。
using (var ts = new TransactionScope())
{
... // your old code
ts.Complete()
}