0Pricing
SQL Academy · レッスン

楽観的ロックと悲観的ロック

SELECT ... FOR UPDATE(悲観的ロック)と、バージョン列 / WHERE updated_at = ?(楽観的ロック)のパターンを比較します。

「楽観的ロックと悲観的ロック」はCoddyKit上の無料SQL Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSQL Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 SQL Academyコースには全4レッスンが含まれています。

2つの同時実行戦略

  • 悲観的 — 読み取り時に行をロックし、他の処理から変更できないようにする
  • 楽観的 — ロックせず、更新時に行が変更されていないことを確認する

悲観的:SELECT ... FOR UPDATE

今ロックし、後で書き込みます。

BEGIN;
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;
-- other transactions cannot lock or update this row
-- compute new balance...
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

FOR SHARE

読み取りロックです。他の処理は読み取れますが、書き込めません。

SELECT * FROM orders WHERE id = 1 FOR SHARE;
-- others can SELECT FOR SHARE but cannot UPDATE

悲観的ロックの長所と短所

長所:動作を理解しやすく、リトライが不要です。
短所:同時実行性が低下し、ロック待ちやデッドロックが発生する可能性があります。

楽観的:バージョン列

バージョンとともに読み取り、WHERE version = expected を付けて書き込みます。

BEGIN;
SELECT id, balance, version FROM accounts WHERE id = 1;
-- compute new balance...
UPDATE accounts
   SET balance = ?, version = version + 1
WHERE id = 1 AND version = ?;
-- check rows affected: 0 means someone else updated, retry

updated_atを使った楽観的ロック

明示的なバージョン列の代わりに updated_at を使う、同じ考え方です。

UPDATE accounts
   SET balance = ?, updated_at = NOW()
WHERE id = ? AND updated_at = ?;

-- If updated_at has changed in the meantime, 0 rows affected — retry.

楽観的ロックの長所と短所

長所:同時実行性が高く、待機がありません。
短所:書き込みが失敗してリトライ処理が必要になる場合があり、競合が表面化するのは UPDATE の時点だけです。

悲観的ロックを選ぶ場合

次のような場合に適しています。

  • 競合の多い行で競合が頻発する短いトランザクション
  • 金銭の送金 — 処理を途中まで進めたくない場合
  • 競合が起きる可能性が高い長時間実行の処理

楽観的ロックを選ぶ場合

次のような場合に適しています。

  • 競合がまれな、読み取り中心のワークロード
  • クライアントがリクエスト間で行を保持するステートレスAPI
  • モバイルやオフラインで編集してから同期する場合

ハイブリッド:FOR UPDATE NOWAIT

ロックを試み、ロック中ならすぐに失敗させて、ユーザーにリトライしてもらいます。

SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT;
-- ERROR if someone else holds it — user sees a friendly retry message

アドバイザリーロック

特定の行に結び付かない、アプリケーションレベルのロックです。

SELECT pg_try_advisory_xact_lock(hashtext('order:42'));
-- True if you got the lock, false otherwise — useful for cross-row coordination.

ロック対象へのインデックス付けを忘れない

WHERE 列にインデックスがない状態で FOR UPDATE を使うと、想定より多くの行がロックされる場合があります(ロックされるのは一致した行だけでなく、スキャンされた行です)。

ロックタイムアウト

lock_timeout を設定して、いつまでも待機しないようにします。

SET lock_timeout = '5s';
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- ERROR if lock not acquired in 5 seconds

まとめ

悲観的ロックは行をロックし、楽観的ロックは書き込み時に確認します。

  • 悲観的:FOR UPDATE — 単純ですが、同時実行性が低下する
  • 楽観的:バージョン列 — より高い同時実行性が得られるが、リトライが必要
  • ワークロードに応じて選び、必要に応じて組み合わせる

クイックチェック

ECサイトで在庫を減らす処理では、競合が頻発します。一般的に、どのロック戦略がより安全ですか。

よくある質問

「楽観的ロックと悲観的ロック」レッスンは無料ですか?

はい。「楽観的ロックと悲観的ロック」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、SQL Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 SQL Academyコースには全4レッスンが含まれています。

「楽観的ロックと悲観的ロック」で何を学びますか?

SELECT ... FOR UPDATE(悲観的ロック)と、バージョン列 / WHERE updated_at = ?(楽観的ロック)のパターンを比較します。 ブラウザで直接実行するハンズオンコードでSQL Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

SQL Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSQL Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「楽観的ロックと悲観的ロック」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSQL Academyレッスンでコードを書いて実行できますか?

はい。すべてのSQL Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ACID特性とアノマリー
  2. 分離レベル:READ COMMITTED、REPEATABLE READ、SERIALIZABLE
  3. デッドロック:検出と回避
  4. 楽観的ロックと悲観的ロック
← SQL Academyに戻る