甘いもん好きおやじのブログ

日常の面白いことを描きます。

【ORACLEのロックについての検証2】for update

テーブルにupdate文を投げたまま戻ってこないことってよくありますね。
ORACLEタイムアウトが設定されてないので、対象テーブルのロックが解除されるまで、ずーっと待つことになります。
アプリの不具合で、対象テーブルのロックが保持されたままになった場合、後の処理が待ちになってしまいます。

そうならないためにも、
これから更新しようとするテーブルが既にロックされているかどうか調べてから、処理をするように作るのもありだと思います。

そんなとき、select * from xxx for update文を使って、更新対象テーブルがロックされてるか確認します。

■検証

★セッションA
・テスト用テーブル作成
SQL> create table a(a number);

表が作成されました。

・テスト用データ作成
SQL> insert into a value(1);
insert into a value(1)

SQL> insert into a values(1);

1行が作成されました。

SQL> insert into a values(2);

1行が作成されました。

SQL> insert into a values(3);

1行が作成されました。

SQL> insert into a values(4);

1行が作成されました。

SQL> insert into a values(5);

1行が作成されました。

SQL> commit;

コミットが完了しました。

・テストテーブルをupdate
SQLupdate a set a=1;

この時点で、テストテーブルaにロックが掛かってます。

★セッションB
別セッションで、ロック中のaテーブルを参照します。

・30秒待って、aテーブルへのロックを取得できなければ、諦める
09:31:11 SQL> select * from a for update wait 30;
select * from a for update wait 30
              *
行1でエラーが発生しました。:
ORA-30006: リソース・ビジー; WAITタイムアウトの期限に達しました。

・aテーブルへのロックを取得できなければ、即諦める
09:31:43 SQL>
09:31:43 SQL> select * from a for update nowait;
select * from a for update nowait
              *
行1でエラーが発生しました。:
ORA-00054: リソース・ビジー。NOWAITが指定されているか、タイムアウトしました

・aテーブルへのロックを取得できるまで待つ
SQL> select * from a for update;
※CTRL + Cで止めるまで待ってます。


その後・・・・

★セッションA
・テスト用テーブルの処理を確定し、ロック解除
SQL> rollback;

ロールバックが完了しました。

★セッションB
・テスト用テーブルのロックが解除されたので、セッションBがロックを獲得し、テーブルaの結果が返ってくる
SQL> select * from a for update;

         A
----------
         1
         2
         3
         4
         5


select * from a for update;で、テーブルaがロックされます。
select * from aは、テーブルaへのロックを取得しないので、結果が返ってきます。