16bit!

エンジニアじゃなくなっちゃった人が何かを書くブログ

【SQL】【Oracle】SELECT FOR UPDATE NOWAITの注意点

OracleではSQLの発行時、select文に”for update”と付けることによって
抽出したデータを行単位でロックすることができます。

select * from TBL
where col_1 = 'A'
and col_2 = 'B'
for update


なお、ロック後に該当の行に対して別のセッションからアクセス(更新処理)された場合、
基本的にそのセッションではロックをかけた側のセッションでロックが解除されるまで待機されますが、
これを待機ではなく強制的にエラーにする方法もあります。

select * from TBL
where col_1 = 'A'
and col_2 = 'B'
for update nowait;


それが"NOWAIT"。
上記のように末尾に"nowait"と付けることで、セッションを待機ではなく即時エラーにすることが可能です。


ですが、ここで1つ注意点が。
この”nowait”、つけるのはロックする側ではなく、ロック中の行にアクセスする側です。

つまり、この”nowait”は、
「行ロックがかかっているデータにアクセスした場合に即時エラーにするためのオプション」であって、
他のセッションからのアクセス時に即時エラーになるようにロックをかけるためのオプションではない。
ということです。

したがって、UPDATE文やDELETE文などを即時エラーにしたい場合、
現状ではその手前で"SELECT FOR UPDATE NOWAIT"を投げて事前検査するしかありません(不便です)。


ちなみに、NOWAITでのアクセス時、既にロックされている場合に発生するエラーは、
Oracleでは「ORA-00054: リソース・ビジー、NOWAITが指定されていました。」で、
JavaではSQLExceptionでキャッチできます。
(より詳細にはNestedSQLExceptionらしいので、それをキャッチした方が良いのかもしれません)。