排他ロックの基礎
  (C) 2001 A c t o r .N e t Soft Ware



 以下に公開するソースなどの著作は 篠田直樹 に復帰します。
原則として無許可で使用する事が出来ますが、ここに書かれている内容を
直リンクや引用などであたかも第三者が作成した様に見せたり如何なる事情でも金銭が発生する行為を禁止します。



DBを扱う上で最も初歩的で重要なテクニックがロックである。
ロックを行うには主に2種類が存在し、悲観的ロックと楽観ロックが存在する。
両者は別名で「物理排他」「論理排他」とそれぞれ呼ばれている。

ではこの違いは一体なんぞや。
そもそも排他の基礎的な知識として排他を行わなければならない場所を初心者が
理解するには多少難しい。
色々なロックの手法や扱いがある為に、どのタイミングでロックを行えば良いのか 筆者の経験では過去に参考書を見ても混乱していた。
排他を行う所は限られていて、排他を行う所はただ一つ。
UPDATEを行う部分である。
INSERT文を発行した時はキーが同一であれば弾かれるDBレイアウトでなければならない。
よって、排他の概念はINSERT、UPDATEで必要でも実際のロジックとしてはUPDATEにしか必要ない。

この基本を根底から覆すDBは今の所、基本的にはAccess + SQL Server で構築したシステムでしかない。
Accessを使うシステムはサーバーシステムを使ったとしても基本的に小規模なシステムにしか使えない。
(そもそも、Accessには扱えるレコード数のキャパやVBA自体の制約があって、その制約を超える業務内容の仕様には耐えられない。)
だから、基本的にAccessからデータを読み込む場合には大抵、レコードを直接触って、触る部分が自動的に
レコードロックされる機構になる事を把握しておかなければならない。
こういった作りは、画面周りのソースを簡略化し、開発効率をUPさせるテクニックとして使われる。
しかし規模が大きくなる程、直接テーブルを参照して変更をかける様な事は都合が悪く物理的に出来なくなる。
こういったシステムでUPDATEを掛ける手段としては共有する為に敢えて、ワークテーブルを作り、UPDATEを掛ける
時にワークテーブルへInsertして、データベース側のトリガとストアドで対象テーブルのレコード更新を掛ける。
この様にする事で更新タイミングをずらせるので擬似排他が出来る。
もし、先々に規模が大きくなると考えられるなら、予めselect文で拾って間接的にテーブルを使う事をお勧めする。


クライアントマシンが2台以上あると同じ入力・更新画面から更新処理を行う時、
同一のタイミングで更新が入った時にどちらかの更新処理が優先される。
しかし、更新を行ったユーザにはどっちが優先されたのはさっぱりわからない。
例えば元々100円×5を入荷した品物に対して、この画面を見てA氏は100×8に書き換え、
B氏は100×1に書き換えたとする。
A氏は3つ入荷を加算したい意図があった、一方でB氏は4つの入荷を取り消したい意図がある。
これを同時に実行した場合はどうなるか。
どちらか一方は正しいが、どちらか一方は意図しない結果が帰るのだ。
結果として、その書き込まれたデータが本当に正しいものなのかも疑問だ。

さて、本題に移ってまず楽観ロックについてはレコードロックを行わない。
レコードロックを行わないという事はSELECT文が通って書き込みの画面が開いていても
対象のデータを見る事が出来るという事である。
悲観ロックとは物理的にレコードロックを行う為、書き込みの画面が開いている限り、
対象のデータはロックされるので見る事も書き込む事も出来ない。
業務アプリで使う場合、大抵は楽観ロックを使う。
理由は一つの画面に占有されて他の所でも作業が出来ないとなると使い勝手が悪いからだ。
もう一つはレコードロックを物理的に掛けてしまうと解除するまでロックが入ったままになり
対象の画面に不都合が起こった時、他の画面などで使いたいのに管理者が対応しない限り
システム的にまともに扱えない状態が起こりうる。
以下に主な使い方を挙げる。

楽観ロック
画面からの入力を行う場合。
(毎回、レコードロックすると他の画面が使えなくなる、又はシステムが止まる
 可能性もあるので悲観ロックは必要最小限に留める。)

悲観的ロック
バッチ処理などの重い処理を行う場合。
(確実に処理を行わなければならない場合に使う。
 例えば年次処理を行う時に楽観ロックで処理していると、特に夜間も画面系使う様な業種の場合は
 作り上の問題で何らかのタイミングで月次や年次処理に関係するマスタ系のレコードが更新されてしまうと
 今まで計算したものに信頼性がなくなってしまう。(例えば月次や年次処理で使うルールになる様なレコードデータ。)
 通常、システム的に画面入力された内容は確定されず、候補として保存される。
 理由は赤黒伝票(訂正経歴と実際に入れたいデータ)のカラミがあるからだ。
 その候補を拾って期間設定などのルールに従って月次や年次処理を行う。
 バッチを走らせる場合は重い処理が殆どなので、通常は夜間に自動起動をして実行する。)


画面系での悲観ロックの基本概念
画面を開いた時点で読み込んだデータのレコードが何時に書き込まれたのかをメモリに退避しておく。
UPDATEを行う場合は、対象のレコードを先に見て初めに取得した日時時間と同一かどうかをチェックする。
もし、同一であればその時に日時と時刻を書き換える。
アンマッチが起きた場合は、書き込み処理を中止してユーザにその旨を伝えるメッセージを出す。
この時に入力した画面の内容は残念ながら破棄するしかない。
もし、破棄をしたくない場合は、更新された履歴内容を読み取ってユーザに判断して貰い、
それでも書き込むかどうかを催促するロジックを組む必要がある。

もし、ロックを行わない場合はどうなるか・・・
デットロックという症状が起こる、つまり両方を書き込もうとして書き込む前に
データベース自身がロックを掛けたまま書き込めずに終了してしまい、ロックが掛かった状態になる。
当然、このまま放置していると対象のテーブル自体がロックされるので、データベースに設定した
ロックの強制開放時間が過ぎるまでロック解除が出来ないか、或いはコマンドで強制的にロック解除する必要がある。
仮に書き込まれたとしてもどっちが先に書き込まれたか不明なのでその入力内容が正しいか
帳票を出すなりしない限り確実に判断する手法がない。


Copyright (C) 2001 A c t o r .N e t Soft Ware All Right Reserved