4章では、楽観的ロックと悲観的ロックの基本的な考え方を解説しました。この章では、それ を応用し、Oracleに実装する方法を検討します。
5.1. 悲観的ロックを Oracle に適用する
これは社員番号7369のSMITHさんの給料を変更する例です。
Aさん Bさん
1 SELECT empno, ename, sal FROM emp WHERE empno=7369 FOR UPDATE NOWAIT;
EMPNO ENAME SAL
‑‑‑‑‑‑ ‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑
7369 SMITH 800
2 この間に、アプリケーション上でデータを変 更します。SMITHさんの給料を300追加するこ とにします。
SELECT empno, ename, sal FROM emp WHERE empno=7369 FOR UPDATE NOWAIT;
行: 1:にエラーが発生しました。ORA-00054:
リソースビジー、NOWAITが指定されていま した
3 UPDATE emp SET sal = sal + 300 WHERE empno=7369;
COMMIT;
4 SELECT empno, ename, sal FROM emp
WHERE empno=7369 FOR UPDATE NOWAIT;
EMPNO ENAME SAL
‑‑‑‑‑‑ ‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑
7369 SMITH 1100 1.社員番号7369の行をNOWAITつきでロック読みとりします。
2.社員番号7369の行をNOWAITつきでロック読みとりします。しかしAさんがロックしている
のでエラーになります。
3.アプリケーション上の変更をデータベースに反映し、変更を確定します。ここでロックが解放 されます。
4.Aさんがロックを解放したので、Bさんはロック読み取りが可能になりました。
悲観的ロックでは長時間ロックを保持するので、NOWAITオプションを使用するほうが一般的 です。ただし相手がロックを解放する直前であってもエラーになるので、「3回リトライしてロ ックを獲得できなかったらメッセージを表示する」などの仕組みにすることもあります。
5.2. 楽観的ロックを Oracle に適用する
楽観的ロックでは、変更したいデータがほかのユーザーに変更されていないことを調べる必要 があります。調べるには次の方法があります。
l 列データをすべて比較する。
l 変更番号を持ち、それを比較する。
それぞれの特徴は次のとおりです。どちらのほうが優れているというものではありません。ア プリケーションやテーブルの特性に応じて使い分けます。
方式 特徴
列データを比較する ・本来のテーブル構造を変更する必要がない。
・カラム数が多いと比較に時間がかかる。
・レコード長が長いと比較に時間がかかる。特にバイナリーデータ。
・現在の画面で必要とするカラム数よりも表のカラム数が多いときに は、必要以上のカラムを毎回 SELECT することになり、パフォーマ ンスが低下する。
変更番号を使う ・変更番号を比較するだけなので簡単。
・変更番号を採番するロジックが必要。
・変更番号を持つカラムを追加する必要がある。つまりそれだけ余分 にディスク領域が必要になる。
表 2 変更検出方式による違い
ここでは列データを比較する方法を紹介します。変更番号を使う方法も、全体の流れは同じで す。
Aさん Bさん 1 SELECT * FROM emp
WHERE empno=7369;
EMPNO ENAME SAL
‑‑‑‑‑‑ ‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑
7369 SMITH 800
2 この間に、アプリケーション上のデータを変 更する。SMITHさんの給料に300追加する。
SELECT * FROM emp WHERE empno=7369;
EMPNO ENAME SAL
‑‑‑‑‑‑ ‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑
7369 SMITH 800 3 SELECT * FROM emp
WHERE empno=7369 FOR UPDATE;
EMPNO ENAME SAL
‑‑‑‑‑‑ ‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑
7369 SMITH 800
この間に、アプリケーション上のデータを変 更する。SMITHさんの給料を300追加する。
4 行データを比較。
5 UPDATE emp SET sal = sal + 300 WHERE empno=7369;
COMMIT;
6 SELECT * FROM emp
WHERE empno=7369 FOR UPDATE;
EMPNO ENAME SAL
‑‑‑‑‑‑ ‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑
7369 SMITH 1100
7 行データを比較。
1.社員番号7369の行を読み取ります。
2.Aさんはアプリケーション上でデータを変更します。Bさんは社員番号7369の行を読み取りま
す。
3.ほかのユーザーに変更されていないことを確認するために、読み取りロックをかけます。
4.1で読んたデータと、3で読んだデータを比較します。
5.変更されていなかったので、アプリケーション上の変更をデータベースに反映し、コミットし ます。
6.こんどはBさんが、ほかのユーザーに変更されていないことを確認するために、読み取りロッ クをかけます。
7.2で読んだデータと6で読んだデータを比較します。ほかのユーザーに変更されていることがわ かったので、現在アプリケーション上で加えた変更を破棄し、FOR UPDATEなしで最新のデ ータを読み取ります(つまり2に戻る)。
ここでは NOWAIT オプションを使用していません。楽観的ロックではロックによる待ち時間
が短いため、NOWAITオプションを使用しないほうが一般的です。ただし、同じ表に対し大規模 なトランザクションを同時に実行する可能性があるときには、NOWAITオプションを使用し、長 時間の待ち状態を防止します。