デッドロックが起きたら、どう調べてどう防ぎますか

DB の記録からぶつかった 2 つのトランザクションと、それぞれがどの順で何をロックしたかを特定し、ロックを取る順番をそろえる、トランザクションを短くする、と答える問い。ゼロにはできないので、片方が取り消されたときにトランザクションごとやり直す作りまで話します。

まず 4 択で考える

2 問

答えに入れるべき考えを選びます。選ぶと、すぐに正誤と解説が出ます。そのあと下の欄で、自分の言葉で答えてみます。

  1. 問 1複数の商品を買う処理でデッドロックが出ている。根本の手として正しいものはどれか

  2. 問 2アプリがデッドロックのエラーを受け取った。アプリの動きとして正しいものはどれか

2 問中 0 問に答えました

答えてみる

面接官に「デッドロックが起きたら、どう調べてどう防ぎますか」と聞かれたつもりで、答えを見る前に自分の言葉で、声に出して答えてみます。

解説を読む

聞かれ方から関連するコースまで、この問いの解説を全部ここに置いています。

こう聞かれます

  • 「デッドロックが起きたら、どう調べてどう防ぎますか」
  • 「デッドロックとは何ですか。ロックの待ちとは何が違いますか」
  • 「デッドロックのエラーが出たとき、アプリは何をすべきですか」

面接官が見ている点

  • 2 つのトランザクションが、互いの持つロックを待ち合う形だと説明できるか
  • DB の記録から、どの SQL がどの順でぶつかったかを特定する手順を持っているか
  • ロックの順番をそろえる、トランザクションを短くする、といった根本の手を言えるか
  • ゼロにはできないと分かり、やり直しの作りまで考えているか

短い答え

  • デッドロックは、2 つのトランザクションが互いに相手の持つロックを待ち、どちらも進めなくなる状態です。多くの DB は自分で見つけて、片方を取り消します。
  • 調べるときは、DB が残すデッドロックの記録から、ぶつかった SQL と、それぞれがどの順で何をロックしたかを特定します。
  • 防ぐには、ロックを取る順番をそろえ、トランザクションを短くします。それでも起こりうるので、取り消された側はトランザクションごとやり直す作りにします。

この問いを含む分野をレッスンで練習する

レッスンを開く

少し詳しい答え

どうして起きるか

在庫を 2 つ持つ注文を考えます。

  1. 注文 A のトランザクションが、商品 1 の行をロックする
  2. 注文 B のトランザクションが、商品 2 の行をロックする
  3. A が商品 2 をロックしようとして、B を待つ
  4. B が商品 1 をロックしようとして、A を待つ

A は B を、B は A を待っているので、どちらも永遠に進めません。PostgreSQL や MySQL (InnoDB) は、この待ち合いの輪を見つけると、片方のトランザクションをエラーで取り消し、もう片方を進めます。

ただのロックの待ちは、相手が終われば進めます。デッドロックは、待っていても決して終わらない点が違います。

どう調べるか

DB はデッドロックの中身を記録します。PostgreSQL では起きるたびにサーバーの記録に出て、MySQL では SHOW ENGINE INNODB STATUS の結果に直近の 1 件が出ます。そこから次を読み取ります。

  • ぶつかった 2 つのトランザクションが、それぞれ流していた SQL
  • それぞれが、どの表のどの行 (どのインデックス) のロックを持ち、何を待っていたか

次に、その SQL を流しているアプリのコードを探し、ロックを取る順番が呼び出しによって入れ替わる所を見つけます。起きた回数と時間帯も監視で見て、特定の処理や時間に偏っていないかを確かめます。

どう防ぐか

  • ロックを取る順番をそろえる上の例なら、どの注文も商品の id の小さい順に更新すれば、輪ができません。いちばん効く手です
  • トランザクションを短くする 中で外の API を呼んだり、利用者の入力を待ったりしません。ロックを持つ時間が短いほど、ぶつかる機会が減ります
  • ロックする行を減らす条件に合うインデックスが無いと、DB は多くの行を読んでロックすることがあります。更新の条件に合うインデックスを用意します
  • 最初にまとめてロックする後で更新する行を、トランザクションの初めに順番どおり SELECT ... FOR UPDATE でロックしておく手もあります

SQL クエリ

-- どの注文も商品の id の小さい順にロックする
BEGIN;
SELECT id, stock FROM products
WHERE id IN (1, 2)
ORDER BY id
FOR UPDATE;
UPDATE products SET stock = stock - 1 WHERE id = 1;
UPDATE products SET stock = stock - 1 WHERE id = 2;
COMMIT;

やり直しの作り

順番をそろえても、別の処理の組み合わせで起こることはあります。だから、デッドロックのエラーを受けたら、トランザクションを初めからやり直す作りにします。途中の SQL だけをやり直すのではなく、トランザクションごとです。回数に上限を付け、何度も起きるなら記録に残して原因を探します。やり直しても困らないように、外へのメールや通知はトランザクションが確定した後に送ります。

トレードオフ

ロックの順番をそろえるには、コードのあちこちの更新の順を決まりとして守る必要があり、レビューで見る物が増えます。最初にまとめてロックすると、ロックを持つ時間が延び、同時に動ける数は減ります。起きる頻度と、起きたときの害の大きさを見て、どこまで手を入れるかを決めます。

話す例は架空の例で構いません。「複数の商品を買う処理で、カートの順に在庫を減らしていたためデッドロックが出ていたので、id の順に並べてから減らすようにした」のように話せると伝わります。

よくある間違い

  • ロックの待ちの時間を延ばして済ませるデッドロックは待っても終わりません。輪ができる順番を直します
  • 取り消されたトランザクションの、途中の SQL だけをやり直す 取り消しで前の SQL も無かったことになっています。トランザクションごとやり直します
  • トランザクションの中で外の API を呼ぶ ロックを持つ時間が延び、ぶつかる機会が増えます

深掘りの問い

  • 「デッドロックとロックの待ちの時間切れは、どう見分けますか」デッドロックは DB が待ち合いの輪を見つけた時点で片方を取り消し、専用のエラーになります。時間切れは決めた時間まで待ってから失敗し、エラーも別です、と答えます
  • 「分離レベルを上げれば防げますか」上げると取るロックが増え、かえって起きやすくなることがある、と答えます
  • 「ORM を使っていると、ロックの順番が見えにくいときは」実際に流れる SQL を記録に出し、更新の順番を確かめる、と答えます

確認日 2026年10月30日書き手 小尾 知希 (講師)

技術面接問題の一覧へ戻る