VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
ERROR 1213: Deadlock found when trying to get lock; try restarting transaction で強制終了します。
デッドロックが起こる仕組み
典型的なパターン: 2 つのトランザクションが逆の順序で行をロックします。デッドロックログの読み方
最新のデッドロックは、常に InnoDB のステータス出力で確認できます。LATEST DETECTED DEADLOCK セクションを探してください。両方のトランザクション、それぞれが保持していたロック、待っていたロック、およびどちらのトランザクションがロールバックされたかが示されます。
- どの 2 つのクエリが競合しているか
- どのテーブルとインデックスが関係しているか
- どちらのトランザクションが犠牲者(ロールバックされた側)か
デッドロック防止のパターン
一貫した順序で行をロックする
上のデッドロックは、A が行 1 の次に行 2 をロックし、B が行 2 の次に行 1 をロックするために起こります。両方のトランザクションが常に ID の昇順でロックすれば、循環は形成されません。トランザクションを短く保つ
長いトランザクションはロックを長く保持するため、競合が発生する時間が増えます。トランザクションの中では最小限の作業だけを行ってください。SELECT … FOR UPDATE で事前にロックする
トランザクションが行を更新する予定なら、UPDATE でロックの衝突に気づくのではなく、SELECT の時点でロックします。デッドロック時に再試行する
デッドロックは並行システムでは想定されるものです。アプリケーションの正しい対応は、ERROR 1213 を捕捉してトランザクション全体を再試行することです。
ギャップロックとネクストキーロック
InnoDB は、デフォルトのREPEATABLE READ 分離レベルでファントムリードを防ぐために、ギャップロックとネクストキーロックを使います。これらの広いロックは、デッドロックの可能性を高めます。
READ COMMITTED は行ロックのみを使い(ギャップロックなし)、デッドロックの頻度を減らします。トレードオフは、ファントムリードを許すことです。ほとんどの OLTP ワークロードでは、デッドロックの影響を受けやすい操作に対して READ COMMITTED は妥当な選択です。
ロック待ちのタイムアウト
すべてのロック競合がデッドロックというわけではありません。トランザクション B が単に A のロックを待っていて A が遅い場合、B はinnodb_lock_wait_timeout 秒(デフォルト: 50)後にタイムアウトします。エラーは ERROR 1205: Lock wait timeout exceeded です。
よくある質問
現在のすべてのロックと、誰が待っているかを見るにはどうすればよいですか?
data_locks は、現在保持または要求されているすべてのロックを示します。data_lock_waits は、どのスレッドがどのスレッドをブロックしているかを示します。
InnoDB は常にデッドロックを即座に検出しますか?
InnoDB のデッドロック検出器は、ロックの競合が発生したときに同期的に実行されます。検出はほぼ瞬時です。innodb_deadlock_detect = OFF で無効にして innodb_lock_wait_timeout だけに頼ることもでき、一部の高並行ワークロードはパフォーマンスのためにそうしますが、一般的ではありません。
すべてのデッドロックを防げますか?
いいえ。デッドロックは、ロックを行う並行トランザクションの根本的な性質です。一貫したロック順序と短いトランザクションで頻度を減らすことはでき、デッドロックに対する再試行ロジックは常に書くべきです。トラブルシューティング
関連項目
- MySQL のトランザクション — デッドロックを可能にするトランザクションモデル
- InnoDB がデータを格納する仕組み — InnoDB の行レベルロックが内部でどう機能するか