e-learning、オラクル研修、LMS(学習管理システム)のiStudy

e-learning、オラクル研修、LMS(学習管理システム)のiStudy

第56回 「自律型トランザクション」

2013.05.02

こんにちは、インストラクターの蓑島です。いい季節になってきましたね。

さて、今回は「自律型トランザクション」という簡単な機能をご紹介します。

この機能を使えば、一連の長い処理の、一部分の処理だけを確定させることができます。
たとえトランザクションがロールバックされても、その部分の処理だけは別のトランザクションとして、もとのトランザクションとは別に、確定(COMMIT)させることができるのです。

では、単純な例で早速デモしてみます。
一連の処理の一部分だけを確定できる様子が簡単に確認できるデモです。

ストーリーは、まず「TEST01表」という簡単な表を用意します。
そこに4行INSERTするのですが、途中の2行だけは自律型トランザクションでINSERTします。
そして、ROLLBACKすると、4行のうち、自律型トランザクションでINSERTした途中の2行だけは確定されており、取り消されずに残るという内容です。

では、TEST01表を作ります。A列、B列だけの単純な表とします。

-----  ここから --------------------------
SQL> CREATE TABLE  TEST01
  2  (  A  NUMBER,
  3     B  VARCHAR2(10));

表が作成されました。
-----  ここまで -------------------------

次に、TEST01表にINSERTを行う簡単なプロシージャを作成します。
このプロシージャに対して自律型トランザクションの指定をしておきます。

-----  ここから --------------------------
SQL> CREATE OR REPLACE PROCEDURE PROC1 ( P1 IN NUMBER,
  2                                      P2 IN VARCHAR2)
  3  IS
  4    PRAGMA AUTONOMOUS_TRANSACTION;       -- ★自律型トランザクションの指定
  5  BEGIN
  6    INSERT INTO TEST01(A,B) VALUES (P1,P2);
  7    COMMIT;     -- 自律型トランザクションの最後は、必ず、COMMITかROLLBACK
  8  END;
  9  /

プロシージャが作成されました。
-----  ここまで -------------------------

このプロシージャはパラメータで指定した値でTEST01表にINSERTするわけですが、注目していただきたいのは、4行目の「PRAGMA AUTONOMOUS_TRANSACTION; 」の指定です。
このキーワードがあることで、このプロシージャ内の処理は、自律型トランザクションであり、呼び出し元のトランザクションからは独立しているということになります。
したがって、7行目のCOMMITは、このプロシージャ内の処理だけを確定させるものであり、呼び出し元のメイントランザクションを確定させることはありません。

なお、自律型トランザクションは上記の例のように、必ずサブプログラムとして定義してください。
つまり、無名ブロックや、ネストしたブロックという形では、実装できません。
たとえ、ローカルな(つまり宣言部で宣言した)サブプログラムでも結構ですので、必ずプロシージャなどのサブプログラムとして、定義してください。

では、早速この機能を確認しましょう。
まず、TEST01表に4行INSERTしますが、一部の行のINSERTは、上記のプロシージャを使います。
以下の例をご覧ください。

-----  ここから --------------------------
SQL> BEGIN
  1      -- 普通のINSERT(メイントランザクションの開始)
  2     INSERT INTO TEST01(A,B) VALUES (10,'AB');   
  3     --- 自律型トランザクションで20番と30番の行をINSERTして確定
  4     PROC1(20,'CD'); 
  5     PROC1(30,'EF');
  6     -- メイントランザクションにもどり40番の行をINSERT
  7     INSERT INTO TEST01(A,B) VALUES (40,'GH');   
  8  END;
  9  /

PL/SQLプロシージャが正常に完了しました。

SQL> SELECT * FROM TEST01;

         A B
---------- ----------
        10 AB
        20 CD        -- 自律型トランザクションで確定した行
        30 EF        -- 自律型トランザクションで確定した行
        40 GH

↑ 現在4行ある

SQL> ROLLBACK;

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

SQL> SELECT * FROM TEST01;     

         A B
---------- ----------
        20 CD
        30 EF

↑ ROLLBACKしても、自律型トランザクションでINSERTした行は取り消されない
-----  ここまで -------------------------

いかがですか?
確かにロールバックしても自律型トランザクションで、INSERTした行は取り消されていませんね。

簡単に解説します。
まず最初に、10番の行をINSERTしました。
これによりまだトランザクションが開始されていなければ、トランザクションが開始されます(メイントランザクション)。
次に、自律型トランザクションのプロシージャで、20番と30番の行をINSERTします。
このINSERT処理は自律型トランザクションなので、メイントランザクションに影響を与えずに確定します。
最後にまたメイントランザクションに戻り、40番の行をINSERTしました。
よって最初と最後の行(10番と40番)は、まだ確定していないわけです。

このような次第なので、最後にROLLBACKすると、10番と40番の行は取り消され、自律型トランザクションでINSERTした20番と30番の行は取り消されずに残ったわけです。

このように、たとえメイントランザクションをROLLBACKしても、一連の処理の一部分だけを確定できる機能ということで、わかりやすいですね。

この機能の代表的な実装例としては、セキュリティのために、監査の記録を残す事例があげられます。
例えば、「誰が、いつ、どの表の、どの行の、どの列を、どの値に更新したかという記録を監査表にINSERTする」といった処理を、自律型トランザクションで行えば、最終的にメイントランザクションが取消されても、監査記録だけは残るわけです。
セキュリティ対策として望ましいですね。まさに監査記録のINSERT処理にピッタリです。

それでは、今回はここまでにしたいと思います。

次回は上記でご紹介した、自律型トランザクションを使って監査の記録を残す処理を、データベーストリガーを使って実装する事例を紹介したいと思います。
自律型トランザクションはCOMMITを伴う処理なので、データベーストリガーからは使用できないように思われるかもしれませんが、ちゃんとできます。

次回はその理由も含めてデータベーストリガー周りの部分を解説いたします。
ご期待ください。

先頭へ戻る