【ひかんてきろっく】

悲観的ロック とは?

💡 「衝突するかもしれない」と慎重に構えて、読み取り時からロックをかける方式
📌 このページのポイント
悲観的ロック(Pessimistic Lock) トランザクション A トランザクション B SELECT FOR UPDATE ロック 取得 処理中... ロック保持期間 COMMIT ロック解放 SELECT FOR UPDATE 待機(ブロック) ロック 取得・処理 トランザクション A トランザクション B ブロック / 待機 ロック取得・解放 先にロックを取得し、競合を事前に防止する方式 データの整合性を確実に保証するが、並行性が低下する
悲観的ロックの仕組み
ひよこ ひよこ

悲観的ロックって具体的にどう書くの?

ペンギン先生 ペンギン先生

SQLでは「SELECT * FROM products WHERE id = 1 FOR UPDATE」と書く。このSELECTを実行したトランザクションがCOMMITまたはROLLBACKするまで、id=1の行は他のトランザクションから更新できなくなる。読み取りはデータベースによって挙動が違うけど、更新は確実にブロックされる。

ひよこ ひよこ

どんな場面で使うの?

ペンギン先生 ペンギン先生

典型的なのは在庫管理。「在庫を確認→在庫を減らす」の間に他の人も同じ在庫を減らすと、実際より多く売れてしまう(オーバーセリング)。FOR UPDATEで在庫行をロックすれば、確認と減算の間に他の処理が割り込めないから安全なんだ。

ひよこ ひよこ

ロックしている間、他のリクエストはどうなるの?

ペンギン先生 ペンギン先生

ロックが解放されるまで待たされる。ロック取得のタイムアウトを設定しておかないと、永遠に待ち続ける可能性もある。「NOWAIT」オプションを付けるとロックが取れなければ即エラーにできるし、「SKIP LOCKED」で他がロック中の行をスキップすることもできるよ。

ひよこ ひよこ

デッドロックってどういう状態?

ペンギン先生 ペンギン先生

トランザクションAが行Xをロックして行Yを待ち、同時にトランザクションBが行Yをロックして行Xを待つ。お互いが相手を待って永久に進めない状態がデッドロックデータベースはこれを検知して片方を強制ロールバックする。防ぐにはロックを取得する順序を統一するのが基本なんだけど、アプリケーションが複雑になるとロック順序の統一が難しくなる。特に複数テーブルにまたがるトランザクションでは「テーブルAの後にテーブルBをロックする」というルールをチーム全員が守る必要があって、コードレビューでも見落としやすいポイントなんだ。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
悲観的ロックって出てきたら「読み取り時からロックをかけて他の変更をブロック、競合が多い場面向け」と思えばだいたいOK!
📖 おまけ:英語の意味
「Pessimistic Locking」 = 悲観的な(Pessimistic)ロック(Locking)
💬 「衝突するかもしれない」と悲観的に考え、事前にロックをかけて防ぐ方式
← 用語集にもどる