ADO.NET を使うと楽観的同時実行制御を容易に実装できる事、そして、超有名な「楽観的ロックでいいじゃん!」のお陰で、楽観的同時実行制御は、特に Web アプリケーション開発では広く使われているのではないでしょうか。勿論、大概のアプリケーションでは楽観的同時実行制御で十分なのかもしれません。しかし「楽観的同時実行制御こそが正義だ」と盲信されかねない空気に警鐘を鳴らす為にも、今一度考えてみましょう。
まず、楽観的同時実行制御、悲観的同時実行制御とは何なのかを整理してみます。先でも紹介した大西彰さんの記事には、悲観的ロックと楽観的ロックを対比してまとめてくれています(もう 2 年以上前の記事ですね。読んだ事がない人は是非一読を)。
「楽観的ロックでいいじゃん! 」より
悲観的ロック:ステートフルなロック
更新したい対象のリソースを照会して取得した直後から更新が終わるまでロックを維持すること => ロック時間は長時間で、ロックは独占的
楽観的ロック:(ほぼ)ステートレスなロック
更新したい対象のリソースを照会してもロックはかけず、本当に更新が必要になった段階でその対象リソースをロックすること => ロック時間は短時間で、ロックは非独占的
「データベースのコンテキストで言うロック」の話で言えば、その通りでしょう。更に、どうして「悲観的」「楽観的」と表現するのかも付け加えて「同時実行制御」という概念で整理してみます。
悲観的同時実行制御
衝突が頻繁に発生する事が前提の同時実行制御
楽観的同時実行制御
衝突が殆ど起こらない事が前提の同時実行制御
つまり「競合・衝突が全く、あるいは殆ど起こらないために、衝突に関しては楽観的に考えてよい」のが楽観的同時実行制御であり、「競合・衝突が殆どにおいて発生し、トランザクション量も多いため、衝突に関しては悲観的に考えなければならない」のが悲観的同時実行制御です。
ここが肝要であり、よく勘違いされるのが「DBMS のロックメカニズムを使うことが悲観的同時実行制御である」という事です。そのせいか、長時間ロックを回避する為に Web アプリケーション開発では楽観的同時実行制御を大前提に設計をしてしまう事が多々あるようです。しかし、トランザクション量が多く、競合・衝突が頻発するにも関わらず楽観的同時実行制御を行ってしまうと、極端に使い勝手の悪いアプリケーションになってしまいます。また、予約システムのように仮予約されたチケット(または座席)が、いざ購入の段になって「他の人に獲られました」ではクレームの嵐です。仮予約チケットは、他の人が見れないようにロックする必要があります。かといって長時間トランザクション(対話型トランザクション)に DBMS のロックメカニズムを使う訳にはいきません。
ここで考えられるのが、独力で同時実行制御を作り込む事です。「.NETエンタープライズWebアプリケーション開発技術大全〈Vol.5〉トランザクション設計編」では「業務排他制御」と表現されています。「悲観的ロックを使わないで悲観的同時実行制御を行う」とでも表現しましょうか。テーブルに排他制御専用の列を 2 つ 3 つ追加し、編集ステータスや編集開始日時などをチェックすれば良いだけで、実装自体は比較的容易(※1)です。
そうやって考えてみると、クライアントユーザー数が多いであろう Web アプリケーションの方が楽観的同時実行制御には向いていないとさえ言えます(※2)。楽観的同時実行制御が向いているのは、マスタデータメンテナンス等を行う、クライアントユーザー数の限られた Windows アプリケーション等(※3)ではないでしょうか。
「Web アプリケーションでは悲観ロックはあり得ない。楽観同時実行制御こそが正」と決めつける前に、よくよく仕様を揉んでみましょう。その要件は楽観的に考えられるでしょうか?
(※1)実装は容易でも、業務フローの難易度は高くなるでしょう。
(※2)勿論、ユーザー数が多くても、大半のユーザーが参照アクションしか行わないのであれば、その限りではありません。
(※3)勿論、Web アプリケーションでも在り得ますが。