第18回: 悲観ロックと楽観ロック — 競合更新を「防ぐ」か「検知」するか

章: 第4章: データ整合性と運用

2人が同時に同じレコードを更新したら、どちらの変更が残りますか?

在庫管理・予約システム・残高更新——複数のユーザーが同時に同じデータを書き換えようとする場面では、何も対策しなければ後からの更新が前の更新を上書きしてしまいます。これを防ぐのが「悲観ロック」と「楽観ロック」という2つのアプローチです。

2つのロック戦略の考え方

悲観ロックは「必ず競合が起きる」と仮定して、更新前にロックを取得して他のトランザクションをブロックします。楽観ロックは「競合はめったに起きない」と仮定して、更新時にバージョン番号を確認し、変更があれば処理を中断します。

悲観ロック・楽観ロックの比較

観点 悲観ロック 楽観ロック
競合発生時の挙動 競合を事前にブロック 競合を検知して中断
実装方法 SELECT ... FOR UPDATE version 列などで条件付きUPDATE
向いている用途 高頻度更新・在庫管理 低頻度更新・編集フォーム
デメリット ロック保持中の待ち時間が発生 リトライ処理が必要
デッドロックリスク ある(ロック順序に注意) 低い

チェックポイント: 更新頻度と競合の可能性を最初に評価しましょう。「同時に同じレコードを更新するユーザーがどれくらいいるか」を見積もり、高頻度なら悲観ロック、低頻度なら楽観ロックを検討します。どちらの場合も、失敗時のリトライまたはエラー通知の設計を忘れずに。

コードサンプル


-- 悲観ロック
START TRANSACTION;
SELECT * FROM inventory WHERE product_id = 10 FOR UPDATE;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 10;
COMMIT;

まとめ & 次のステップ

  • 悲観ロックは競合を事前にブロックし、楽観ロックは競合を検知して中断します
  • 業務の更新頻度と競合可能性に合わせて使い分けましょう
  • 悲観ロックはロック時間を最小化するよう、トランザクションの範囲を絞ります
  • 楽観ロックはリトライ設計とセットで実装しましょう
  • どちらの方式も、失敗ケースを明示的にテストして動作確認します

次回は デッドロックの見つけ方と対策 を学びます。避けられないデッドロックをどう検知し、どう設計で減らすかを見ていきましょう。

Related Articles