2016年5月4日水曜日

【ロックについての検証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
SQL> update 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へのロックを取得しないので、結果が返ってきます。

0 件のコメント:

コメントを投稿