【でっどろっく】
デッドロック とは?
最終更新:
💡 互いに必要なロックの解放を待って進めない状態
処理が互いのロックなどの解放を待ち、進めなくなる状態。2つの処理の待ち関係、ロック順序の統一、DBの検出と中断、タイムアウトの限界を解説します。
📌 このページのポイント
- 互いが持つロックを待つと処理が進めなくなる
- 行単位のロックでも起こる
- ロックの取得順序をそろえることが予防に役立つ
- 検出・中断・再試行は、使う仕組みの仕様に従う
どんなときに、待ち合うの?
処理AがXを持ってYを待ち、処理BがYを持ってXを待つ例だよ。互いが進めないので、必要なロックも解放されない。片方が長いだけの待ちと、この循環した待ちを区別する。
テーブルではなく、行をロックすれば防げる?
行ロックでも起こる。PostgreSQLの公式例では、2つの取引が別々の行を先に更新し、それぞれ相手が持つ行を更新しようとして待ち合う。ロックを小さくするだけでは予防を保証できない。
DBは、自動で直してくれる?
PostgreSQLは検出すると、関係するトランザクションの一つを中断して他を進める。ただし、どれが中断されるかには依存できない。アプリはエラーを処理する必要があり、全ての仕組みで同じ動作とは限らない。
どう予防するの?
複数の対象をロックする全ての処理で、例えばXからYという順序をそろえる方法がある。関連する処理全体で守ることが大切だ。取得後に長く待つ処理も避け、必要以上にロックを持ち続けないようにする。
タイムアウトなら、必ず解決?
待つ時間を制限するだけでは足りない。失敗した処理を中断し、持っているロックを解放するなどの後始末が必要だ。再試行する場合も、トランザクション全体や外部への処理の扱いを確認するんだ。
もっと詳しく知りたい人へ
中断されたトランザクションは、途中のSQLだけ再試行する?
途中だけを機械的に再実行せず、中断されたトランザクションの状態と製品の仕様を確認します。PostgreSQLではデッドロックにより中断されたトランザクションを再試行する対応が示されています。外部送信などDB外の処理がある場合は、重複して実行しない設計も必要です。
図の矢印は、ロックを取れたという意味?
いいえ。矢印は相手が持つロックの解放を待つ方向です。AからB、BからAの待ちが循環しているため、介入がなければ先へ進めない例を示しています。
まとめ:ざっくりこれだけ覚えればOK!
「デッドロック」って出てきたら「互いに必要なロックの解放を待って進めない状態」と思えばだいたいOK!
📖 おまけ:英語の意味
「Deadlock」 = 行き詰まり・膠着状態
💬 ここでは、処理がお互いのロックなどを待つことで進めなくなる状態を扱います。単に実行が遅いこととは違います。