3.4.14 複数トランザクションで検索と更新をする場合
複数トランザクションで同一の表を検索及び更新する場合の一般的な処理方法と注意事項について説明します。
(1) 一般的な処理方法
SELECT文で更新対象行を特定し,UPDATE文で更新するトランザクションを実行する場合,SELECT文を実行する前に同一トランザクション中で,LOCK文を用いて排他モードで表に対して排他制御を行うか,又はSELECT文の排他制御のモードを次のどちらかの方法で排他モード(EX:Exclusive)にするかしてください。
-
クライアント環境定義に次のどちらかを指定し,SELECT文にFOR UPDATE指定をする
-
PDISLLVLに2を指定する
-
PDFORUPDATEEXLOCKにYESを指定する
-
-
SELECT文の排他オプションにWITH EXCLUSIVE LOCKを指定する
SELECT文の排他制御のモードを排他モードにする場合の例を次に示します。
- (例)
-
次の表「在庫テーブル」から「在庫状態」が「在庫確保中」の行を検索します。該当する行があった場合は,「在庫状態」を「在庫あり」に変更します。
表3‒26 例・在庫テーブル 在庫ID(主キー)
在庫名
在庫状態
20345678
ネクタイ
在庫確保中
20345679
シャツ
在庫あり
20345680
靴下
在庫なし
20345681
ズボン
在庫確保中
20345682
スカート
在庫あり
20345683
パンツ
在庫確保中
DECLARE CUR1 CURSOR FOR SELECT 在庫状態 FROM 在庫テーブル WHERE 在庫状態='在庫確保中' WITH EXCLUSIVE LOCK FOR UPDATE OF 在庫状態 OPEN CUR1 WHILE(SQLCODE == 0){ FETCH CUR1 INTO :在庫状態 UPDATE 在庫テーブル SET 在庫状態='在庫あり' WHERE CURRENT OF CUR1 } CLOSE CUR1
(2) 検索する行に対して更新する行が非常に少ない場合
SELECT文でヒットする行に対してUPDATE文で更新する行が少ない場合,SELECT文の排他オプションにSHARE LOCKを指定することで,他トランザクションからも参照できるようになるため,同時実行性を向上できます。ただし,他トランザクションと更新する行が重なり,排他制御のモードが共有モードから排他モードに遷移することによってデッドロックが起こるおそれがあるため,注意してください。
(3) 排他の掛かる行を減らすために事前に無排他で検索する場合
SELECT文を無排他検索にすることで,「検索する行に対して更新する行が非常に少ない場合」よりもさらに同時実行性を向上できます。ただし,無排他検索をしてからUPDATE文を実行するまでの間に検索した行がほかのトランザクションによって更新される可能性があります。この場合,データの取り出しで読み込む値が,探索条件に合致しない値になることがあります。UPDATE文を正しく実行するため,無排他にしたSELECT文の探索条件を,UPDATE文又は排他制御のモードが排他モードのSELECT文で再評価してください。
無排他にしたSELECT文の探索条件を,排他制御のモードが排他モードのSELECT文で再評価する場合の例を次に示します。
- (例)
-
無排他のSELECT文に指定した探索条件「在庫状態='在庫確保中'」をWITH EXCLUSIVE LOCKの指定があるSELECT文で再評価して,他トランザクションによる変更がないことを確認します。他トランザクションによる変更がなければ更新をします。
DECLARE CUR1 CURSOR FOR SELECT 在庫ID FROM 在庫テーブル WHERE 在庫状態='在庫確保中' WITHOUT LOCK OPEN CUR1 WHILE(SQLCODE == 0){ FETCH CUR1 INTO :在庫ID_WITHOUTLCK /* 行を絞り込むためのUAP側の処理 */ ・ ・ ・ DECLARE CUR2 CURSOR FOR SELECT 在庫状態 FROM 在庫テーブル WHERE 在庫ID=:在庫ID_WITHOUTLCK AND 在庫状態='在庫確保中' WITH EXCLUSIVE LOCK FOR UPDATE OF 在庫状態 OPEN CUR2 FETCH CUR2 INTO :在庫状態_WITHLCK IF(SQLCODE == 0){ UPDATE 在庫テーブル SET 在庫状態='在庫あり' WHERE CURRENT OF CUR2 } CLOSE CUR2 } CLOSE CUR1