Open1
【記事草案】楽観ロックと悲観ロックについて

参考になった記事
- https://zenn.dev/shuhei_takada/books/3ff66325f45adc/viewer/2bf43c
- https://zenn.dev/igaiga/books/rails-practice-note/viewer/ar_transaction_lock#楽観的(optimistic)ロック
- https://edgeapi.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html
楽観ロック(楽観的排他制御)
概要
- データそのものに対して直接ロックを行わず、ロックキーを参照し、更新対象のデータがデータ取得時と同じ状態であることを確認してから更新することでデータの整合性を保証する排他制御の方式のこと。
詳細
楽観ロックとは、めったなことでは他者との同時更新は起きないであろう、という楽観的な前提の排他制御。
データそのものに対してロックは行わずに、更新対象のデータがデータ取得時と同じ状態であることを確認してから更新することで、データの整合性を保証する方式。
楽観ロックを使用する場合は、更新対象のデータがデータ取得時と同じ状態であることを判断するために、Versionを管理するためのカラム(Versionカラム)を用意する。更新時の条件として、データ取得時のVersionとデータ更新時のVersionを同じとすることで、データの整合性を保証することができる。
更新対象のデータがデータ取得時と同じ状態であることを判断するためのカラムを、「ロックキー」と呼ぶ。ロックキーは、Versionカラム以外にも更新日時等のタイムスタンプを用いることもできる。
メリット
- ロック待ちが発生しないため、システムのスループットが向上する。
- そのため、主に読み取りが多く、書き込みが少ないテーブルに適している。
デメリット
- 同時に複数のユーザーが同じデータを更新しようとする場合、更新の失敗が頻発する可能性がある。
悲観ロック(悲観的排他制御)
概要
- データを取得する際にロック(共有ロックや排他ロック)をかけ、他のトランザクションからの更新を防止する排他制御の方式のこと。
詳細
他者が同じデータに頻繁に変更を加えるであろう、という悲観的な前提の排他制御。更新対象のデータを取得する際にロックをかけることで、他のトランザクションから更新されないようにする方式。悲観ロックを使用する場合は、トランザクション開始直後に更新対象となるレコードのロックを取得する。ロックされたレコードは、トランザクションが、コミットまたはロールバックされるまで、他のトランザクションから更新されないため、データの整合性を保証することができる。
データのロックはRDBMSの「SELECT 〜 FOR UPDATE」を利用して実現されるのが一般的。悲観ロックでは、ロックの解放漏れがあると、いつまで経っても他者が操作できないということに繋がるため、データ更新後はロックの解放を必ず行うこと。
いわゆる共有ロックや排他ロックはこの悲観ロックに分類される。
メリット
- データの一貫性と整合性を確実に保つことができる。
- そのため、主に書き込みが多く、競合が頻発するシステムに適している。
デメリット
- ロック待ちが発生するため、システムのパフォーマンスに影響を与えることがある。
- ロックの解放漏れが発生すると、データベースのデッドロックやパフォーマンス低下を招く恐れがある。