デッドロック回復を提供するORMツールを知っていますか?デッドロックは悪いことだと私は知っていますが、適切な量の負荷が与えられると、どのシステムでもデッドロックに悩まされることがあります。SQL Serverでは、デッドロックメッセージに「トランザクションを再実行してください」と表示されているため、デッドロックステートメントの再実行がORMの望ましい機能であると思われます。
5 に答える
デッドロックのために失敗したトランザクションを自動的に再実行するための特別な ORM ツールのサポートについては知りません。ただし、ORM によってロック/デッドロックの問題への対処が大きく変わるとは思いません。まず、デッドロックの根本原因を分析してから、デッドロックが回避されるか、少なくとも減少するようにトランザクションとクエリを再設計する必要があります。トランザクションの (部分) に対して適切な分離レベルを選択する、ロック ヒントを使用するなど、改善のための多くのオプションがあります。これは、ORM よりもデータベース システムに大きく依存します。もちろん、ORM で、微調整されたコマンドなどにストアド プロシージャを使用できる場合に役立ちます。
これがデッドロックを完全に回避するのに役立たない場合、または実際の修正を今すぐ実装してテストする時間がない場合は、もちろん、save/commit/persist またはその他の呼び出しの周りに try/catch を配置するだけで済みます。失敗したトランザクションが「デッドロックの犠牲者」であることを示す場合は例外をキャッチし、数秒間スリープした後、単純に保存/コミット/永続化を呼び戻します。デッドロックは多くの場合、同じリソースに対して競合するトランザクションの一時的なピークがあることを示しているため、数秒待つことをお勧めします。同じトランザクションを何度もすばやく再実行すると、状況がさらに悪化する可能性があります。
同じ理由で、同じトランザクションを 1 回だけ再実行することを確実にすることはおそらくないでしょう。
実際のシナリオでは、この種の回避策を実装したことがあり、「デッドロックの犠牲者」の約 80% が 2 回目で成功しました。しかし、デッドロックの実際の理由を解決するために、より深く掘り下げることを強くお勧めします。これらの問題は通常、ユーザーの数に応じて指数関数的に増加するためです。それが役立つことを願っています。
デッドロックが予想されますが、SQL Server は他のデータベース サーバーよりもこの点で劣っているようです。まず、デッドロックを最小限に抑えるようにしてください。SQL Server プロファイラーを使用して、その理由とそれに対して何ができるかを調べてみてください。次に、可能であれば、同じトランザクションで更新を行った後に読み取らないように ORM を構成します。最後に、Spring と Hibernate を一緒に使用する場合は、この状況を監視するためにインターセプターを配置できます。MethodInterceptor を拡張し、interceptorNames の下の Spring Bean に配置します。インターセプターが実行されたら、invocation.proceed() を使用してトランザクションを実行します。例外をキャッチし、再試行する回数を定義します。
私が取り組んだ 1 つのシステムは、ユーザーが保存を押したときにデータベースにコミットされる「コマンド」に基づいていました。次のように機能しました。
While(true)
start a database transaction
Foreach command to process
read data the command need into objects
update the object by calling the command.run method
EndForeach
Save the objects to the database
If not deadlock
commit the database transaction
we are done
Else
abort the database transaction
log deadlock and try again
EndIf
EndWhile
任意の ORM で同様のことができる場合があります。ORM は当時新しすぎたため、社内のデータ アクセス システムを使用しました。
ユーザーがシステムと対話している間に、トランザクションの外部でコマンドを実行します。次に、他の人が行った変更に対処するために、上記のようにそれらを再実行します (「保存」を使用した場合)。コマンドが変更する行の適切な理想がすでにあったため、ロック ヒントまたは「select for update」を使用して、トランザクションの開始時に必要なすべての書き込みロックを解除することもできました。(デッドロックの数をさらに減らすために、更新する行のセットを短くしました)
o/r マッパーはこれを検出できません。デッドロックは常に DBMS 内で発生しており、他のスレッドや他のアプリによって設定されたロックが原因である可能性があります。
コードの一部がデッドロックを引き起こさないようにするために、常に次のルールを使用してください。 - トランザクションの外でフェッチを行います。したがって、最初にフェッチし、次に処理を実行してから、挿入、削除、更新などの DML ステートメントを実行します。メソッド内のすべてのアクション、またはトランザクションを含む/操作する一連のメソッドは、データベースへの同じ接続を使用する必要があります。これが必要なのは、たとえば、書き込みロックが同じ接続を介して実行されるステートメントによって無視されるためです (同じ接続がロックを設定するため ;))。
多くの場合、デッドロックは、コードがトランザクション内でデータをフェッチして NEW 接続を開く (ロックを待機する必要がある) か、トランザクション内のステートメントに別の接続を使用するために発生します。
私はざっと見ましたが(あなたもそうであることは間違いありません)、休止状態が少なくともこれを提供していることを示唆するものは何も見つかりませんでした. これはおそらく、ORM が解決しようとしている問題の範囲外であると考えているためです。
デッドロックに問題がある場合は、ここに投稿されているいくつかの提案に従って解決してください。その後、すべてのデータベース アクセス コードが、デッドロックを検出してトランザクションを再試行できる何かでラップされていることを確認する必要があります。