web-dev-qa-db-ja.com

TransactionScopeでNHibernate

NHibernateでTransactionScopeを使用する方法の概要を教えてもらえますか?セッション/ IEnlistmentNotificationなどで何か特別なことをする必要がありますか?これを機能させるには?心配すべき落とし穴はありますか?たとえば、休止状態のトランザクションをすべて置き換えることはできますか?

var transaction = session.BeginTransaction();
try
{
    // code
    transaction.Commit();
}
catch (Exception)
{
    transaction.Rollback();
}

これとともに?:

using (var scope = new TransactionScope())
{
    // code
    scope.Complete();
}
33
Andy White

私はしばらくの間nHibernate2.1を使用しており、いくつかの本番環境の問題とかなりの数のバリエーションを試した後、 NHibernateおよびTransactionScopeとの接続のリークを回避する に従って次の方法に落ち着きました。

        using (var scope = new TransactionScope(TransactionScopeOption.Required))
        {
            using (var session = sessionFactory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                // do what you need to do with the session
                transaction.Commit();
            }
            scope.Complete();
        }

MSMQとWCFを使用しているため、アンビエントトランザクションを使用する必要がありました。

Session.BeginTransaction()を使用しないと、接続リークが発生することがわかりました。また、トランザクションをコミットした後にセッションを再利用すると、競合状態が発生することもわかりました(nHibernateはスレッドセーフではなく、DTSCのコミット/ロールバックはバックグラウンドスレッドで発生します)。

18
Iain

さまざまなベンダーを使用してこれをテストしましたが、正常に機能します。 「scope.Complete()」がない場合、トランザクションはロールバックされます。複数の永続的なリソースがある場合は、関係するマシンをMSDTCで実行する必要がある場合があります。その場合、MSDTCは周囲のADO.NETトランザクションを自動的に検出し、すべてを管理します。

7
Adam Fyles

SQL Server 2005/2008などの軽量トランザクションマネージャーの使用をサポートする接続プロバイダーを使用している場合、上記は問題なく機能します。

SQL Server 7/2000を使用している場合、1つのデータベース/リソースにアクセスしただけでも、すべてのトランザクションが分散トランザクションになります。これはおそらくほとんどの場合あなたが望むものではなく、パフォーマンスの面で高価になります。

したがって、接続プロバイダーとデータベースサーバーの組み合わせがTransactionScopeでの使用に適しているかどうかを確認してください。

6
user133599

すでに述べているように、いくつかの制約を尊重する限り、NHibernateトランザクションをこれに置き換えることができると思います。

  • 適度に新しいNHibernateバージョン( > = 3.1 )を使用します。
  • 基盤となるADO.NETデータプロバイダーは、TransactionScopeをサポートする必要があります(SQL-Server、Oracle> = 10、ODP.NETの場合はOK)。
  • NHセッションをTransactionScope内に作成して、確実に参加できるようにします。
  • NHibernateを処理する フラッシュ 手動で。 ここ および ここ も参照してください。
  • 分散トランザクションの準備をします。 1つのスコープで複数のセッションを作成すると、最初はローカルトランザクションが分散トランザクションに昇格する可能性があります。これは、ODAC11.2.0.3.20を使用するOracle11.2DBの同じ接続文字列でも発生することがわかりました。 SQL-Server 2008 R2では、プロモートしませんでした。 (ところで、これは、ローカルトランザクションではnullであるTransaction.Current.TransactionInformation.DistributedIdentifierを見るとわかります。)分散トランザクションにはいくつかの利点がありますが、コストが高く、設定するのに余分な手間がかかります。 ( ここ Oracleでこれを行う方法を参照してください)。 Oracleでプロモーションが発生しないようにするには、接続文字列に「 プロモーション可能なトランザクション =ローカル」を設定します。一部のコードがそうしようとすると、これにより例外が作成されます。

それがすべてだといいのですが;-)

PS:Oracleの詳細を追加したのは、私の懸念や他の人が恩恵を受ける可能性があるためです。

5
Piper

NH-2107 に関連するコメントのFabio Mauloによると:

TransactionScopeを使用でき、NHのトランザクションも引き続き使用する必要があります。 TransactionScopeの使用は、NHのトランザクションの使用を回避することを意味することを読んだところはどこですか?

NHibernateのトランザクションを明示的に使用する必要はないと思いましたが、明らかにそれがベストプラクティスです

1
emertechie

また、TransactionScopeを使用している場合は、NHibernate2.1にアップグレードしてください。 NHがTransactionScopeとの良好な統合を実際に得たのは、2.1だけです。

1
Rohit Agarwal