
検索実行時にテーブルをロックしたい
1つのトランザクションの中で、検索(SELECT文)を発行した時に、ロックをしたいことがあるかと思います。
というか、必要が生じました。
とある処理で、数値が不整合を起こす障害の原因調査をしたのですが、これが酷い。
処理自体は、あるテーブルの金額項目に対して、ユーザーが画面から入力した数値を加算するっていうものです。
仕様書に書いてるのは、こんな内容。
1.SELECT文でテーブルAからデータ抽出
2.1で取得した金額に、画面で入力した金額を加算
3.2の結果をテーブルAに上書きする。
1で取得した数値を加工して上書きするって仕様なんですから、SELECT文を発行する時にロックをかけないといけません。
しかし、この処理を実装したプログラマは違う考えがあったらしく、ロックを掛けなかったようです。
...おい、ふざけるなよ。
行ロック
というわけで、SELECT文の発行と同時に行ロックを実行します。
SELECT文の最後に「FOR UPDATE」と追加すれば、検索される行がロック(悲観的ロック)されます。
このロックは、COMMIT or ROLLBACK された時点で解除されます。
SELECT
A.支店コード,
B.取引先名
FROM
与信マスタ A,
取引先マスタ B
WHERE
A.取引先コード = B.取引先コード
FOR UPDATE
このサンプルでは、「与信マスタ」と「取引先マスタ」がロックされます。
対象テーブルを指定した行ロック
テーブルを結合して対象データを絞りこんでいる時に「FOR UPDATE OF テーブル名.項目名」とすることでどのテーブル(の行)をロックするか設定できます。
下記のサンプルでは項目名まで指定していますが、あくまでも対象となるテーブル(の行)を指定するためのものなので指定した項目だけロックされる(されない)というものではありません。
SELECT
A.支店コード,
B.取引先名
FROM
与信マスタ A,
取引先マスタ B
WHERE
A.取引先コード = B.取引先コード
FOR UPDATE OF A.支店コード
「FOR UPDATE OF A.支店コード, B.支店コード」とカンマで区切れば取引先マスタもロックされます。
ロックが解除されるタイミング
FOR UPDATE によるロックは、COMMIT or ROLLBACK が発行された時点で解除されます。
つまり、トランザクションが終了した時ってことですね。
余談
UPDATE文やDELETE文の場合は、特に何もせずともロックされます。
当然、これもCOMMIT or ROLLBACK が実行された時点で解除されます。
...障害発生時の条件だと、別にSELECT文でデータ抽出なんかせずに、UPDATE文で加算してやれば良かったんじゃないかと思います。
まぁ、今さらですがね。
スポンサードリンク


