2

私は、ORMとしてNHibernateを使用して小さなASP.NETMVCWebアプリを構築しました。開始するすべてのHTTPリクエストで、セッションを作成し、トランザクションを開いて、リクエストの最後に閉じます。

// Begin request

session = StaticSessionManager.OpenSession();    
session.BeginTransaction();

// End of request

currentSession.Transaction.Commit();
currentSession.Flush();
currentSession.Close();

現在、Facebook/Googleログイン用のDotNetOpenAuthAPIも使用しています。新しいユーザーを登録するために、APIはテーブル(たとえばUserProfile)をいくつかのユーザー情報で更新することを期待しています。これはNhibernateのSave()を介して行っています

session.Save(new UserProfile { UserName = userName });

同じWebリクエストで、DotNetOpenAuth APIは、そのテーブル(UserProfile)から上記の挿入されたデータを読み取ることを想定しています。

NHibernateのSaveがデータベースにある種のロックを適用したため、これはデッドロックシナリオにつながります。SQL Server Management Studioを使用してそのテーブルから手動でデータを読み取ろうとしても、Web要求がタイムアウトするまで待機しているようです。

保存後に明示的なフラッシュを試しました

session.Flush();

しかし、これでもロックを解除することはできません。DotNetOpenAUthAPIが最新のデータを読み取れるようにしたいと思います。

現在、保存後にトランザクションを開始し、後でもう一度開きます。これがベストプラクティスであるかどうか/欠点があるかどうかはわかりません。

4

1 に答える 1

4

いつフラッシュを呼び出すのですか?

デフォルト設定(FlushModeオンISession)では、NHibernateトランザクションを呼び出すCommit()と自動的に変更がフラッシュされます。手動でフラッシュしたい場合もありますがFlush()、トランザクションのコミット後に呼び出すことは、いくつかの理由で不適切です。

  • コミット自体はすでにフラッシュされているので、フラッシュする変更がこれ以上ないことがわかっているので、役に立たない。ただし、NHibernateはそれが役に立たないことを認識していないため、ロードされたすべてのオブジェクトをダーティチェックします。つまり、superflouosフラッシングはパフォーマンスに悪影響を及ぼします。

  • データベースに送信するダーティ状態が実際にある場合、そのような更新はトランザクションの外部で実行されますが、これは通常、私たちが望んでいることではありません。

データベースのロック

通常、データベースがある種のロックを取得すると、トランザクションがコミットまたはロールバックされるまで、そのロックは保持されます。フラッシングはトランザクションを終了しないため、ロックの解放効果はありません。

試みられた解決策

説明から、1つのデータベース接続(NHibernateセッションを介して)を使用してUserProfileを作成し、別のデータベース接続(同じWeb要求内)を使用してそれを読み戻しているように見えます。最初の接続のトランザクションがまだ終了していないため、この後の接続はブロックされます。(データベースはトランザクションが成功するかどうかをまだ認識していないため、明らかにロックする必要があります。)

次のいずれかを実行する方法を見つけてください。

  • ユーザープロファイルを作成するときは、戻る前にコミットできる別のトランザクション(および場合によってはセッション)で作成します。

  • または、ユーザープロファイルの「リードバック」で同じデータベース接続を使用して、同じトランザクション内で実行できるようにします。私はDotNetOpenAuthAPIに精通していませんが、読み取り操作をオーバーライドしてNHibernateを介して実行できるかどうかを確認するか、代わりにsession.ConnectionをDotNetOpenAuthに挿入してみてください。

于 2013-03-03T14:29:31.517 に答える