今日の Pessimistic Offline Lock は、任意のタイミングにおいて、データにアクセスするビジネストランザクションを 1 つに限定することで、データの不整合を防止するパターンです。
Optimistic Offline Lock の問題点は、データの競合に気付くのがトランザクションをコミットする時点まで遅れてしまうことです。結果として、1 つのデータに複数のトランザクションが同時に更新をかけるような状況が多く発生する場合、一人だけがコミットできて、他の人は全員排他エラーが発生するということになりますし、そういった「他の人」は、自分がデータを入力し終わってようやく一息ついたところでエラーが発生するという最悪のユーザ体験をする羽目になります。
Pessimistic Offline Lock では、ビジネストランザクションはデータを使う前に、ロックを取得します。このロックは他のビジネストランザクションが当該データにアクセスすることを防ぎ、データ更新が競合することを防ぎます。更新の競合が多いことが想定されるときに使用するパターンになります。 この Pessimistic Offline Lock の実装は 3 つのフェーズに分かれます。
- 取得するロックの種別を決定する
- ロックマネージャーの構築
- 業務トランザクションがどのようにロックを取得するかを決める
ロックの種別
ロックの種別としては、以下のものがあります。これらについては、システムの並行性、業務要件、コードの単純さを観点に、正しいものを選択する必要があります。
- 排他書込みロック
- 業務トランザクションがデータを編集するときだけロックを取得する。読込については制限しないので、参照トランザクションが単に直近のデータを取得すれば良いのであれば、この種別で十分。
- 排他読込ロック
- 暁霧トランザクションが、直近のデータを保持する場合に選択するロックの種別。このロック種別では、データを取得するタイミングでロックを取得することになり、システムの並行性を強く制限する。
- 読込/書込みロック
- 両者の中間のロック種別。読込ロックと書込ロックの 2 つのロックを利用する。
- 読込ロックと書込ロックは互いに排他的であり、どちらかのロックを取得すると、他方のロックは取得できない。
- 同時並行した読込ロックは許容される。
- つまり、読込ロック取得中は、ロック対象レコードの編集のみ不可となる。
ロックマネージャ
ロックマネージャの責務は、業務トランザクションからのロック要求、ロック解除要求を許可するか、拒否するかを判断することにあります。 これを実現するために、ロックマネージャは、対象データがロックされているか、そして、ロックされているようならそのロックしているユーザが誰かを判断する必要があります。ロックマネージャを構成するのは、ロックとその保有者をマッピングする単一のテーブルになります。
また、消失した業務トランザクションに対するロックタイムアウトの管理も重要です。 クライアントが業務トランザクション中にクラッシュしてしまうと、取得していたロックが外れなくなる場合があります。理想的には、アプリケーションサーバが面倒を見るところです。
業務トランザクションのロックプロトコル
ロックプロトコルでは、以下のような内容を決めます。
- いつロックを取得し、いつ解放するのか
- 何をロックするのか
- ロックが取得できなかった場合どういう挙動をするのか
いつロックを取得するのかについてはデータのロード前、ロックする対象については対象レコードの主キー、ロックの解放はトランザクション完了後、というのが一般的なパターンです。 ロックを取得できなかったときの業務トランザクションについて、最もシンプルなのはそのトランザクションを失敗させることです。Pessimistic Offline Lock では、この失敗についても業務トランザクションの早期に検知できるだめ、おそらくは許容可能でしょう。また、開発者はこのロック取得の試行をより早いタイミングで実施すべきです。