【らっかんてきろっく】

楽観的ロック とは?

💡 「たぶん衝突しないだろう」と楽観的に構えて、更新時に競合チェックする方式
📌 このページのポイント
楽観的ロック(バージョン管理方式) データ: 商品A version = 1 トランザクションA ① READ → version=1 取得 ② データを編集(ローカル) ③ UPDATE WHERE ver=1 → ver=1 一致!成功 ④ version → 2 に更新 トランザクションB ① READ → version=1 取得 ② データを編集(ローカル) ③ UPDATE WHERE ver=1 → ver=2 不一致!失敗 ④ 更新エラー → リトライ 時間 →
楽観的ロックの仕組み
ひよこ ひよこ

楽観的ロックって具体的にどうやるの?

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

テーブルに「version」カラムを追加する。データを読むときにversionも取得して、更新時に「UPDATE ... SET version = version + 1 WHERE id = 1 AND version = 3」のようにWHERE句にversionを入れる。誰かが先に更新してversionが4になっていたら、WHERE条件にマッチせず更新件数が0件になる。これで衝突を検出するんだ。

ひよこ ひよこ

悲観的ロックとどう使い分けるの?

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

楽観的ロックは「衝突はめったに起きない」場面向け。例えばブログ記事の編集やユーザープロフィールの更新。悲観的ロックは「衝突が頻繁に起きる」場面向けで、在庫の減算やチケットの予約に使う。楽観的ロックは待ち時間がないぶん高スループットだけど、衝突が多い場面ではリトライだらけになって逆に遅くなる。

ひよこ ひよこ

ORMだと楽観的ロックは自動でやってくれるの?

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

多くのORMがサポートしている。Railsなら「lock_version」カラムを追加するだけで自動的に楽観的ロックが有効になる。JPAなら@Versionアノテーションを付ける。衝突時はStaleObjectError的な例外が投げられるから、それをcatchしてリトライや「他の人が更新しました」というメッセージを出す処理を書く。

ひよこ ひよこ

楽観的ロックって完璧な仕組みに見えるけど、落とし穴ある?

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

ABA問題というのがある。値がA→B→Aと変わった場合、バージョンチェックだけだと「変わっていない」と判断してしまう可能性がある。バージョン番号をインクリメントする方式なら避けられるけど、タイムスタンプ方式だと同一ミリ秒内の更新で問題が起きることがある。あと、楽観的ロックはあくまで「1つのテーブルの1行」の競合しか検出できないから、複数テーブルにまたがる整合性は別途トランザクションで担保する必要がある。この組み合わせの設計が結構ややこしいんだよね。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
楽観的ロックって出てきたら「ロックせずに更新時にバージョンで競合チェック、衝突が少ない場面向け」と思えばだいたいOK!
📖 おまけ:英語の意味
「Optimistic Locking」 = 楽観的な(Optimistic)ロック(Locking)
💬 「衝突は起きないだろう」と楽観的に考え、実際に衝突したときだけ対処する方式
← 用語集にもどる