【らっかんてきろっく】

楽観的ロック とは?

最終更新:
💡 「たぶん衝突しないだろう」と楽観的に構えて、更新時に競合チェックする方式

編集の間に他の利用者がデータを変える可能性を認め、保存時に読み取った版との一致を確認する方式。バージョン番号などの照合と更新を一つの操作で行い、不一致なら古いデータによる上書きを拒否する。

📌 このページのポイント
古い版による上書きを防ぐ 共有レコード version=1 編集者A 版1を読み取る 手元で編集 編集者B 版1を読み取る 手元で編集 Aが先に保存 版1なら更新 内容と版1→2を同時に Aの保存後にB 版1で保存要求 現在は版2なので拒否 保存成功 最新データを再確認 版の照合と更新は一つの操作で行う 更新処理の待機がなくなる方式ではない
上から下へ時間が進む例。矢印は読み取りと保存までの順序。Aの版照合・データ更新・版の増加は一つの操作で、BはAの保存後に古い版の要求を拒否される。再試行の前に最新データを確認する。
ひよこ ひよこ
楽観的ロックって具体的にどうやるの?
ペンギン先生 ペンギン先生
version=3のデータを読んだら、保存時にその版を条件にするよ。SQLなら「UPDATE ... SET 内容=新しい内容, version=version+1 WHERE id=1 AND version=3」のように、確認と更新を同じ文で行う。対象行が存在しても版が4なら更新されないので、更新件数などで競合を確認するんだ。
ひよこ ひよこ
先に版を調べて、その後に保存すればいい?
ペンギン先生 ペンギン先生
確認と更新を別々にすると、その間に誰かが更新する可能性があるよ。だから版が一致する場合だけ更新する操作にするんだ。更新する経路が版の確認や更新を省いてしまうと、この仕組みで変更を検出できないことがあるよ。
ひよこ ひよこ
悲観的ロックとはどう違うの?
ペンギン先生 ペンギン先生
悲観的ロックは、ほかの更新を待たせてから処理する考え方。楽観的ロックは編集の間に競合が起きることを許し、保存時に検出するよ。競合の多さややり直しの負担で選ぶんだ。楽観的でも、DB内部の更新ロックやトランザクションによる待機は起こりうるよ。
ひよこ ひよこ
ORMなら自動で使えるの?
ペンギン先生 ペンギン先生
対応するORMで設定すると利用できるよ。RailsのActive Recordなら、通常はlock_versionの整数列で版を管理し、競合時にStaleObjectErrorを出す。画面をまたぐ編集では読み取った版も保存要求に渡す必要があるので、列を足すだけでどんな操作も守れると考えないようにね。
ひよこ ひよこ
競合したら同じ内容でリトライすればいい?
ペンギン先生 ペンギン先生
まず最新データを読み直し、ほかの変更と自分の変更をどう扱うか決めよう。古い内容をそのまま再送すると、相手の変更を消すことがあるよ。また、一つのレコードの版確認だけで複数レコードの業務上の整合性がすべて守れるわけではないので、必要なトランザクションや制約も設計するんだ。
ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「楽観的ロック」って出てきたら「保存時に版を確かめ、古い内容で上書きしない工夫」と思えばだいたいOK!
📖 おまけ:英語の意味
「Optimistic Locking」 = 楽観的な(Optimistic)ロック(Locking)
💬 「衝突は起きないだろう」と楽観的に考え、実際に衝突したときだけ対処する方式

参考資料

← 用語集にもどる