2016-03-23 2 views
0

私たちが最後の金曜日をリリースしたとき、私は受け入れられないエラーを受け取りました。エラーメッセージは次のとおりです。NHibernate IStatelessSession CreateQueryの失敗

could not execute update query[SQL: delete from dbo.MyTable where col1=? and col2=? and col3=? and col4=? and col5=?]

私のC#コードは次のとおりです。今

var hqlDelete = "DELETE MyTable m WHERE m.Col1 = :var_1 AND m.Col2 = :var_2 AND m.Col3= :var_3 AND m.Col4 = :var_4 AND m.Col5= :var_5"; 
var deletedEntities = session.CreateQuery(hqlDelete) 
          .SetString("var_1", variable1) 
          .SetString("var_2", variable2) 
          .SetString("var_3", variable3) 
          .SetString("var_4", variable4) 
          .SetString("var_5", variable5) 
          .ExecuteUpdate(); 
transaction.Commit(); 
session.Close(); 

、私は受け入れにテストするときにエラーがトリガされませんでした、言ったように。また、本番データベース(開発席のコード)でテストすると、問題なく動作します。

コードは、Webサービスを呼び出してPOSTに「測定」を行うとトリガーされます。唯一の違いは、私がテストの際にサービスを呼び出すことであり、生産時に他の会社がウェブサービスに測定値を送信するということです。

セッションやトランザクションの量と関係があるかもしれませんが、エラーメッセージに変数が表示される理由を説明できません。

アイデア?あなたが私にこれを手伝うことができるように、私が提供できる情報がありますか?

編集:InnerExeptionはORMを使用する場合は特にデッドロックは、ハードの問題ことができ解決

{"Transaction (Process ID 68) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction."}

+2

最初に、完全な例外スタックを表示します。上の部分は単なる始まりにすぎません...実際の興味深い情報が続きます。 –

+1

Radimが指摘したように、エラーメッセージは不十分です。それは単にそれができないことを伝えます。通常、いくつかの理由があります。 'InnerException'を含む例外の詳細を記録します。 moreがなければ、log4netを追加し、少なくとも警告以上のログを記録するように設定してください。そして、NHibernateは、失敗に関する詳細なログを発行する必要があります。 –

+0

ありがとうございました。私はこれが典型的な間違いか何かを望んでいた。リリース計画(私は月に1回リリースすることができます)に従わなければならないので、デバッグするのはちょっと難しいので、受け入れだけをテストしてください。だから私がlog4netを追加しても、エラーが何であるかを知るには1ヶ月待たなければならない。 – Tjab

答えて

1

です。デッドロックは通常、データベース・オブジェクトのロックが異なるプロセス(またはスレッド)によって同じ順序で取得されず、互いを待つために発生します。

ORMを使用すると、ロックの取得順序を制御できません。あなたはあなたの質問を注文し直すかもしれませんが、これは面倒かもしれません。特にキャッシングによってDBの一部にヒットしない場合。さらに、同じデータベースを使用する他のアプリケーションでも、同じ順序で実行する必要があります。

デッドロックエラーを検出して、メッセージの内容を確認してください。プロセス全体を再試行してください。 NHibernateでは、これは現在のセッションを破棄し、作業単位全体を再試行することを意味します。

データベースがSQL Serverの場合、デッドロックのリスクを大幅に増加させるデフォルト設定があります。無効化はread committed snapshot modeです。データベースでディセーブルになっている場合は、デッドロックのリスクを大幅に削減できます。このモードでは、読み取りコミットされた独立性レベルでの読み取りで読み取りロックの発行を停止できます。

はあなたが

alter database YourDbName 
    set allow_snapshot_isolation on 

alter database YourDbName 
    set read_committed_snapshot on 

でこの設定を有効にして

select snapshot_isolation_state_desc, is_read_committed_snapshot_on 
    from sys.databases 
    where name = 'YourDbName' 

でこの設定を確認することが必要です。このターゲットDB上でどれも実行されているトランザクションを持ちます。もちろん、これにはDBの管理者権限が必要です。

この設定を変更するオプションがないアプリケーションでは、NHibernateのデフォルトの分離モード(connection.isolation configuration parameter)をReadUncommittedに設定するより奇妙な方法が必要でした。私のアプリケーションはほとんどが読み取り専用で、データを読み書きしなければならないいくつかのトランザクションで明示的に分離モードを上げていました(例ではsession.BeginTransaction(System.Data.IsolationLevel.ReadCommitted)を使用しています)。

データベースを使用しているすべてのアプリケーションで現在使用されている分離モードもチェックする必要があります。 (可能であればRepeatableReadとは避けるべきです)これは、適切な最小分離レベルが何かを判断するための各ユースケースを検討しながら、分離レベルを十分に理解する必要があるため、時間がかかるプロセスです。

+0

非常に精巧な答えをありがとう!スナップショットの隔離/コミットの読み取りは実際にはfalse/0に設定されており、この設定はわかりませんでした。 – Tjab

+1

私はコミットされたスナップショット・モードの読取りについて忘れています。これは、tempdbスペースの使用を増やします。あなたのDBAはそれについて知っておくべきです。 –

+0

うーん、あまりにもそれを調べる必要があります。データベースそのものはかなり大きいので、現時点では1つのテーブルで約4億件のレコードを話しています。「テーブル/ dbが大きいほど、tempdbスペースが多く使用されているかどうかはわかりません。 :) – Tjab