Query Go
行やテーブルをロック - ロック (Locking) の使い方・オプション・サンプル

行やテーブルをロック - ロック (Locking)

楽観的ロック vs 悲観的ロック、SELECT ... FOR UPDATE、SKIP LOCKED / NOWAIT の使い分け

概念図

ロック (Locking) diagram

構文

sql
SELECT ... FOR UPDATE [NOWAIT | SKIP LOCKED];

サンプル

FOR UPDATE で対象行を排他ロックし、競合更新を防ぐ

sql
-- 悲観的ロック: 行を排他ロックしてから更新
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- ここで他トランザクションは同じ行を待たされる
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
COMMIT;

楽観的ロック vs 悲観的ロック

  • 悲観的ロック (Pessimistic): 「他が触るはず」と想定し、先に行をロックしてから読み書きする。SELECT ... FOR UPDATE が代表
  • 楽観的ロック (Optimistic): 「ほとんど競合しない」と想定し、更新時に version 列や updated_at を条件に含め、更新件数が 0 なら競合としてリトライ

書き込みが少なく衝突も稀なら楽観的、強い整合が必要・衝突が多いなら悲観的、と使い分けます。

sql
-- 楽観的ロック例 (version 列)
UPDATE products
SET name = 'New', version = version + 1
WHERE id = 10 AND version = 3;
-- 影響行数が 0 ならアプリ側でリトライ

FOR UPDATE と FOR SHARE

  • SELECT ... FOR UPDATE: 排他ロック (X ロック)。他セッションは読みも更新もブロックされる (RDBMS による)
  • SELECT ... FOR SHARE (PostgreSQL / MySQL): 共有ロック (S ロック)。他セッションは読めるが更新はできない。参照整合性をトランザクション内で保ちたいときに使う
  • SQL Server では WITH (UPDLOCK, HOLDLOCK)WITH (ROWLOCK, XLOCK) のヒントで表現

NOWAIT と SKIP LOCKED

ロック待ちの挙動を変えるオプションです。

  • NOWAIT: ロックが取れなかったら待たずにエラー終了
  • SKIP LOCKED: ロック中の行はスキップして、取れる行だけ返す。ジョブキューやワーカー分散で定番

PostgreSQL 9.5+ / MySQL 8.0+ / Oracle 18c+ でサポート(Oracle 11g〜12c では AQ 内部でのみ使われ、ユーザ SQL としては未ドキュメント)。SQL Server は READPAST ヒントで類似機能を提供します。

sql
-- ワーカーがジョブキューから 1 件取り出すパターン
BEGIN;
SELECT id, payload
FROM jobs
WHERE status = 'queued'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;
-- 取れた行を処理してステータス更新
COMMIT;

ロックの粒度

  • 行ロック: 1 行単位。並行性が最大だがロック管理のオーバーヘッドあり
  • ページ/ブロックロック: 複数行をまとめてロック (SQL Server のロックエスカレーション)
  • テーブルロック: テーブル全体。DDL 実行時などに自動取得される
  • ギャップロック / next-key ロック: MySQL InnoDB がファントム防止のために範囲もロックする

大量行を更新すると行ロックが自動的にテーブルロックへ昇格 (escalation) する RDBMS もあり、意図しない待機を招きます。

長すぎるロック保持の危険

ロックはトランザクションの COMMIT または ROLLBACK まで保持されます。以下は典型的なアンチパターンです。

  • トランザクションを開いたまま HTTP レスポンスをユーザーに返してしまう
  • バッチ処理で全行を FOR UPDATE してから重い計算を実行する
  • 外部 API 呼び出しをトランザクション中に行う

ロックを取る区間は最短に、外部 I/O や人間の待ちはトランザクション外で行うことが鉄則です。

関連トピック