NHibernateでTransactionScopeを使用する方法の概要を教えてもらえますか?セッション/ IEnlistmentNotificationなどで何か特別なことをする必要がありますか?これを機能させるには?心配すべき落とし穴はありますか?たとえば、休止状態のトランザクションをすべて置き換えることはできますか?
var transaction = session.BeginTransaction();
try
{
// code
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
これとともに?:
using (var scope = new TransactionScope())
{
// code
scope.Complete();
}
私はしばらくの間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のコミット/ロールバックはバックグラウンドスレッドで発生します)。
さまざまなベンダーを使用してこれをテストしましたが、正常に機能します。 「scope.Complete()」がない場合、トランザクションはロールバックされます。複数の永続的なリソースがある場合は、関係するマシンをMSDTCで実行する必要がある場合があります。その場合、MSDTCは周囲のADO.NETトランザクションを自動的に検出し、すべてを管理します。
SQL Server 2005/2008などの軽量トランザクションマネージャーの使用をサポートする接続プロバイダーを使用している場合、上記は問題なく機能します。
SQL Server 7/2000を使用している場合、1つのデータベース/リソースにアクセスしただけでも、すべてのトランザクションが分散トランザクションになります。これはおそらくほとんどの場合あなたが望むものではなく、パフォーマンスの面で高価になります。
したがって、接続プロバイダーとデータベースサーバーの組み合わせがTransactionScopeでの使用に適しているかどうかを確認してください。
すでに述べているように、いくつかの制約を尊重する限り、NHibernateトランザクションをこれに置き換えることができると思います。
それがすべてだといいのですが;-)
PS:Oracleの詳細を追加したのは、私の懸念や他の人が恩恵を受ける可能性があるためです。
NH-2107 に関連するコメントのFabio Mauloによると:
TransactionScopeを使用でき、NHのトランザクションも引き続き使用する必要があります。 TransactionScopeの使用は、NHのトランザクションの使用を回避することを意味することを読んだところはどこですか?
NHibernateのトランザクションを明示的に使用する必要はないと思いましたが、明らかにそれがベストプラクティスです
また、TransactionScopeを使用している場合は、NHibernate2.1にアップグレードしてください。 NHがTransactionScopeとの良好な統合を実際に得たのは、2.1だけです。