デッドロック
はじめに
前回、共有ロック・専有ロックについて書きましたので、デッドロックについて書いてみます。
デットロックとは
データベースの同時処理(並行処理)でよく起こるトラブルの一つです。
「お互いが相手のロック解除を待ち続けて、永遠に止まってしまう状態」のことです。
データベースでは、複数の人(またはプログラム)が同じデータを同時に扱うことがあります。
このとき、データを壊さないように「ロック」をかけます(🔒)。
それでは、お互いに違うものをロックしていて、次のロックを取りたいのに相手が持っているとどうなるでしょう?
お互いに待ち続け、永遠に処理が終わらなくなります。
これが デッドロック(Deadlock) です。
デッドロックのイメージ図(Deadlock)
お互いが相手のロック解除を待ち続け、処理が永遠に進まなくなる状態を図解しています。
🔒 共有ロック(S)
🔐 専有ロック(X)
⏳ 待ち(待機中)
循環待ちの発生(典型パターン)
トランザクションA
リソース:Table Y
🔐 専有ロック(Bが保持)
リソース:Table X
🔐 専有ロック(Aが保持)
トランザクションB
なぜ起きる?どう防ぐ?
| ポイント | 内容 |
|---|---|
| 発生条件(4つが揃うと危険) | ① 相互排他 / ② 保持しつつ待つ / ③ 奪い取れない / ④ 循環待ち(A⇄B…) |
| 設計で防ぐ |
・ロック取得順序を統一(常に X→Y の順など) ・トランザクションを短く(早くコミット) |
| 運用で和らげる |
・DBのデッドロック検出を活用(片方を中止) ・リトライ処理を実装(自動再実行) |
| 読み取りと書き込み |
共有ロック(S) は同時読み取りOK / 書き込みNG 専有ロック(X) は読み書きともに他者NG |
デッドロックが起きる条件は
- 相互排他:同時に使えないリソース(ロック)
- 保持と待ち:ロックを持ちながら別のロックを待つ
- 奪い取れない:他人のロックを強制解除できない
- 循環待ち:AがBを待ち、BがAを待つ(ぐるぐる)
となります。
対策
デッドロックを防ぐ対策は以下の通りとなります。
| 対策方法 | 内容 |
|---|---|
| ロックの順番を統一する | すべての処理で「同じ順番」でロックを取る(A→Bの順など) |
| トランザクションを短くする | 長時間ロックを保持しない(できるだけ早くコミット) |
| デッドロック検出機能を使う | 多くのDB(MySQL、PostgreSQLなど)は自動的に検出して一方を中止 |
| リトライ処理を組み込む | デッドロック時に再実行するようプログラムで対応 |
まとめ
デッドロックとは、「お互いが譲らず、永遠に順番を待つ状態」です。

