排他制御について(楽観的ロック・悲観的ロック )

f:id:ryoutaku_jo:20190808010623p:plain

【結論】

排他制御とは、データの更新を行う際に、競合を防ぐため、更新が完了するまで他ユーザーのデータ取得/更新を制限する仕組み

・楽観的ロックとは、競合が稀にしか起こらないことを前提とした排他制御。データの取得時には何もせず、更新時に競合をチェックする

・悲観的ロックとは、競合が頻繁に起こる事を前提とした排他制御。データの取得時にはデータをロックし、更新後にロックを解除する

【目次】

【本題】

データの整合性を保つための排他制御

複数ユーザーが同時にデータベースの更新などを行うと、データに不整合が発生する可能性があります。

例えば、商品の在庫状況を管理するシステムがあったとして、はじめに「100個」の在庫があったとします。

Aさんが、商品を「50個」追加しました。

同時に、Bさんが商品を「30個」追加しました

この場合、在庫は「180個」になるべきです。

しかし、排他制御がなされていないと、Bさんの処理は初めの「100個」の在庫に基づいて計算されるので、Aさんの更新が上書きされ、在庫「130個」で登録されてしまいます。

この様な、複数ユーザーによるデータの更新によって、データの不整合が発生するのを防ぐのが、排他制御です。

排他制御には、大きく分けて「楽観的ロック」と「悲観的ロック」という種類が存在します。

楽観的ロックについて

楽観ロックとは、めったなことでは他ユーザーとの同時更新は起きないであろうという想定での排他制御です。

楽観ロックを使用する場合は、Versionを管理するためのカラムを用意します。

Ruby on Railsの場合、lock_versionという名前のinteger型カラムを追加します。このカラムは、レコード更新の度に、値を1ずつ増やします。

データを更新する際に、取得したレコードのVersionと、データベースのレコードのVersionを比較し、versionが異なれば更新しない仕組みになっています。

先ほどの、商品在庫の流れに楽観的ロックを適用した場合、レコードにlock_version「1」が追加されます。

データ取得時、Aさん・Bさんともに、lock_versionが「1」のレコードを取得します。

そして、Aさんの処理が先に実行されるとして、Aさんの取得したレコードのlock_versionと、データベースのlock_versionは、両方とも「1」なので、この時点では問題なく更新が行われます。

この際、データベースのlock_versionは「2」に変わります。

次に、Bさんの処理が実行されますが、Bんの取得したレコードのlock_versionが「1」に対して、この時点でのデータベースのlock_versionは「2」の為、バージョンが違う為、更新が行われません。

メリットとしては、データの取得は問題なく出来るので、他の操作が一時中断してしまうといってことが無いことが挙げられます。

デメリットは、データの更新が出来ない状況(他ユーザーが更新中)であっても、データ取得が出来てしまうので、実際に更新するまで、データ更新が出来ないことに気づけないという点が挙げられます。

データ更新が出来ない場合、再度操作をやり直す必要があるので、作業に時間が掛かるものに対しては不向きです。

悲観的ロックについて

悲観的ロックとは、他ユーザーが同じデータに頻繁に変更を加えるであろうという想定での排他制御です。

悲観的ロックを適用すると、他ユーザーが更新対象のデータを取得出来ない様にロックが掛かります。

ロックはデータの更新処理が完了するまで解除されないので、これにより更新の競合を防ぐことが出来ます。

メリットとしては、データ取得時点で、データ更新が出来ない状況だと気づける点です。これにより再度操作をやり直す手間を防げるの、時間が掛かる操作には有利です。

デメリットは、他ユーザーのデータ取得が制限されてしまうので、利便性が落ちてしまう点です。

参考情報

Active Record クエリインターフェイス - Rails ガイド

排他制御(楽観ロック・悲観ロック)の基礎 - Qiita

《今日の学習進捗(3年以内に10000時間に向けて)》

学習開始からの期間 :242日
今日までの合計時間:2313h
一日あたりの平均学習時間:9.6h
今日までに到達すべき目標時間:2210h
目標との解離:103h
「10,000時間」まで、

残り・・・「7687時間!」