2011-09-14 4 views
1

での線に沿って何か行うアプリケーションを検討し、「挿入はないに存在する」:NHibernateの

var user = session.QueryOver<User>().Where(x => x.Name==name).SingleOrDefault(); 

if (user == null) 
{ 
    user = new User(name); 
    session.Save(user); 
} 

ビジネス・ルールは、ユーザーの名前は一意である必要があることを、これは中UNIQUE INDEXによって支えられていますデータベース。上記のコードはうまくいきます.2人のユーザーが同じ名前で同時に登録しようとするまでは、user == nullとなり、新しいUserを作成してください。コミットする最初のものが成功し、2番目のものが失敗し、データベースから例外が発生します。

このような競合状態を回避する1つの方法は、lock { }ブロックにクリティカルコードをラップすることですが、アプリケーションの複数のインスタンスが同じデータベースに対して機能する場合は役に立ちません。さて、もし私がRDBS(この場合はMS SQL)のロック機構を使用できるのであれば...

これは私が立ち往生したところです。私がNHibernateのドキュメントで読むことができるものから、明示的なロックを要求する私のQueryOver()チェーンにいくつかのヒントを追加することで解決できるかもしれません。私はまだ実際の行がないので、これはテーブルロックでなければなりません。これは可能ですか?方法

また、トランザクションの分離レベルを上げて、必要なロックを自動的に獲得できますか?同じ作業単位内で他の(問題ではない)照会が行われていることを考慮すると、この種の変更がブロック/待機をたくさん導入する可能性があると私は考えています。そうですか?

+0

[NHibernateのトランザクションと競合状態](http://stackoverflow.com/questions/119762/nhibernate-transaction-and-race-condition) –

答えて

0

保存するときと同じNHibernateセッションでクエリを実行することを忘れないでください。これにより、データベースのロック機構を自動的に活用して、同じトランザクションを確実に使用できます。

つまり、というとはトランザクションが失敗するように準備する必要があり、コードはそのケースを正常に処理する必要があります。シリアライズされたブロックやロックを使用すると、複雑さが増しますが、データベースレベルでの失敗の可能性を排除することはできません。

+0

両方のクエリが同じトランザクションがすでに発生しています。例外ログに一意のインデックス違反があります。自動ロックが機能するためにトランザクションの分離レベルを上げる必要がありますか? –

2

アイソレーションレベルをシリアライズ可能に増やします。これは、 'where'句を含め、クエリ全体にわたって読み取りと書き込みの両方のロックを取得します。