社内SEの徒然なる日記

SQLテクニック(行ロック:FOR UPDATE)

検索実行時にテーブルをロックしたい

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文で加算してやれば良かったんじゃないかと思います。
まぁ、今さらですがね。
スポンサードリンク

PageTop

コメント


管理者にだけ表示を許可する