デッドロックに対処する1つの方法は、ランダムな間隔を待機してトランザクションの再実行を試みる再試行メカニズムを用意することです。ランダムな間隔は、衝突するトランザクションが互いにぶつかり続けて、いわゆるライブロックを引き起こさないようにするために必要です。これはデバッグがさらに厄介なことです。実際、ほとんどの複雑なアプリケーションは、トランザクションのシリアル化の失敗を処理する必要があるときに、遅かれ早かれそのような再試行メカニズムを必要とします。
もちろん、デッドロックの原因を特定できる場合は、通常、デッドロックを解消する方がはるかに優れています。そうしないと、 あなたを噛むために戻ってきます。ほとんどすべての場合、デッドロック状態がまれな場合でも、ロックを決定論的な順序で取得したり、より粗いロックを取得したりするためのスループットとコーディングオーバーヘッドは、時折発生する大きな遅延ヒットと突然のパフォーマンスの低下を回避する価値があります。同時実行性をスケーリングする場合。
2つのINSERTステートメントが常にデッドロックしている場合は、インデックスの挿入順序に固有の問題である可能性があります。たとえば、2つのpsqlコマンドウィンドウで次のことを試してください。
Thread A | Thread B
BEGIN; | BEGIN;
| INSERT uniq=1;
INSERT uniq=2; |
| INSERT uniq=2;
| block waiting for thread A to commit or rollback, to
| see if this is an unique key error.
INSERT uniq=1; |
blocks waiting |
for thread B, |
DEADLOCK |
V
通常、これを解決するための最善の行動は、そのようなすべてのトランザクションを保護する親オブジェクトを把握することです。ほとんどのアプリケーションには、ユーザーやアカウントなど、これに適した1つまたは2つのプライマリエンティティがあります。次に必要なのは、すべてのトランザクションがSELECT ...FORUPDATEを介してアクセスするプライマリエンティティのロックを取得することだけです。または、複数に触れた場合は、すべてをロックしますが、毎回同じ順序でロックします(主キーで並べ替えることをお勧めします)。