自律型トランザクション
自律型トランザクションは、別の、メイン・トランザクションによって開始される独立したトランザクションです。
自律型トランザクションは、メイン・トランザクションをコミットまたはロールバックせずに、SQL操作を実行してコミットまたはロールバックします。
図7-1に、メイン・トランザクション(MT)から自律型ルーチン(proc2
)へ制御がどのように流れ、また戻るかを示します。自律型ルーチンは、2つの自立型トランザクション(AT1およびAT2)をコミットします。
ノート:
自律型トランザクションは別のトランザクションによって開始されますが、これはネストしたトランザクションではありません。その理由は次のとおりです。
-
ロックなどのトランザクション・リソースをメイン・トランザクションと共有しません。
-
メイン・トランザクションに依存しません。
たとえば、メイン・トランザクションがロールバックする場合は、ネストしたトランザクションがロールバックするのに対し、自律型トランザクションはロールバックしません。
-
コミットされた変更を、他のトランザクションからすぐに参照できます。
ネストしたトランザクションのコミットされた変更は、メイン・トランザクションがコミットするまで他のトランザクションからは参照できません。
-
自律型トランザクションで例外が呼び出されると、文レベルのロールバックではなくトランザクション・レベルのロールバックが発生します。
ここでのトピック
関連項目:
自律型トランザクションの詳細は、『Oracle Database開発ガイド』を参照してください。
自律型トランザクションのメリット
自律型トランザクションは、開始すると完全に独立します。ロック、リソースまたはコミット依存関係をメイン・トランザクションと共有することはありません。メイン・トランザクションがロールバックする場合でも、イベントや増分再試行カウンタなどのログを取ることができます。
自律型トランザクションは再利用可能なソフトウェア・コンポーネントであるモジュール構造の作成に役立ちます。自律型トランザクションは、ストアド・サブプログラム内部でカプセル化できます。起動元のアプリケーションは、そのストアド・サブプログラムによって実行された操作が成功したか失敗したかを知る必要はありません。
トランザクション・コンテキスト
メイン・トランザクションはそのコンテキストをネストしたルーチンと共有しますが、自律型トランザクションとは共有しません。ある自律型ルーチンが別の自律型ルーチンを(または自身を再帰的に)起動する場合、ルーチンはトランザクション・コンテキストを共有しません。ある自律型ルーチンが自律型ではないルーチンを起動する場合、ルーチンは同じトランザクション・コンテキストを共有します。
トランザクションの可視性
自律型トランザクションによって行われた変更は、自律型トランザクションがコミットすると、他のトランザクションから参照できるようになります。分離レベルがREAD
COMMITTED
(デフォルト)に設定されている場合、メイン・トランザクションが再開すると、これらの変更をメイン・トランザクションから参照できるようになります。
メイン・トランザクションの分離レベルをSERIALIZABLE
に設定すると、その自律型トランザクションによって行われた変更は、再開してもメイン・トランザクションからは参照できません。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ノート:
-
トランザクションのプロパティは、それらが設定されたトランザクションにのみ適用されます。
-
カーソル属性は自律型トランザクションの影響を受けません。
自律型ルーチンの宣言
自律型ルーチンを宣言するには、AUTONOMOUS_TRANSACTION
プラグマを使用します。
このプラグマの詳細は、「AUTONOMOUS_TRANSACTIONプラグマ」を参照してください。
ヒント:
読みやすくするために、AUTONOMOUS_TRANSACTION
プラグマは宣言部の先頭に置きます。(プラグマは宣言部の任意の場所に置くことができます。)
AUTONOMOUS_TRANSACTION
プラグマはパッケージ全体またはADT全体に適用することはできませんが、パッケージ内の各サブプログラムまたはADTの各メソッドに適用できます。
例7-43 パッケージでの自律型ファンクションの宣言
この例では、パッケージ・ファンクションを自律型としてマークします。
CREATE OR REPLACE PACKAGE emp_actions AUTHID DEFINER AS -- package specification FUNCTION raise_salary (emp_id NUMBER, sal_raise NUMBER) RETURN NUMBER; END emp_actions; / CREATE OR REPLACE PACKAGE BODY emp_actions AS -- package body -- code for function raise_salary FUNCTION raise_salary (emp_id NUMBER, sal_raise NUMBER) RETURN NUMBER IS PRAGMA AUTONOMOUS_TRANSACTION; new_sal NUMBER(8,2); BEGIN UPDATE employees SET salary = salary + sal_raise WHERE employee_id = emp_id; COMMIT; SELECT salary INTO new_sal FROM employees WHERE employee_id = emp_id; RETURN new_sal; END raise_salary; END emp_actions; /
例7-44 自律型スタンドアロン・プロシージャの宣言
この例では、スタンドアロン・サブプログラムを自律型としてマークします。
CREATE OR REPLACE PROCEDURE lower_salary
(emp_id NUMBER, amount NUMBER)
AUTHID DEFINER AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE employees
SET salary = salary - amount
WHERE employee_id = emp_id;
COMMIT;
END lower_salary;
/
例7-45 自律型PL/SQLブロックの宣言
この例では、スキーマ・レベルのPL/SQLブロックを自律型としてマークします。(ネストしたPL/SQLブロックは自律型にはできません。)
DROP TABLE emp;
CREATE TABLE emp AS SELECT * FROM employees;
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
emp_id NUMBER(6) := 200;
amount NUMBER(6,2) := 200;
BEGIN
UPDATE employees
SET salary = salary - amount
WHERE employee_id = emp_id;
COMMIT;
END;
/
自律型トランザクションの制御
自律型ルーチンの最初のSQL文でトランザクションが開始されます。1つのトランザクションが終了すると、次のSQL文で別のトランザクションが開始されます。カレント・トランザクションは、最後のコミットまたはロールバックよりも後に実行されたすべてのSQL文で構成されます。自律型トランザクションを制御するには、次の文を使用します(これは現在の(アクティブな)トランザクションのみに適用されます)。
-
COMMIT
-
ROLLBACK
[TO
savepoint_name
] -
SAVEPOINT
savepoint_name
-
SET
TRANSACTION
ここでのトピック
自律型ルーチンの開始と終了
自律型ルーチンの実行部に入ると、メイン・トランザクションは停止します。ルーチンを終了すると、メイン・トランザクションは再開します。
コミットまたはロールバックせずにアクティブな自律型トランザクションを終了しようとすると、データベースによって例外が呼び出されます。例外が未処理になった場合、またはその他の未処理例外が発生してトランザクションが終了した場合、トランザクションはロールバックします。
正常に終了するには、ルーチンはすべての自律型トランザクションを明示的にコミットまたはロールバックする必要があります。ルーチン(またはそれによって起動されたルーチン)に保留中のトランザクションがある場合は、PL/SQLによって例外が呼び出され、保留中のトランザクションはロールバックします。
自律型トランザクションのコミットおよびロールバック
COMMIT
とROLLBACK
はアクティブな自律型トランザクションを終了しますが、自律型ルーチンから抜けるわけではありません。1つのトランザクションが終了すると、次のSQL文で別のトランザクションが開始されます。1つの自律型ルーチンは、複数のCOMMIT
文を発行する場合、複数の自律型トランザクションを含むことができます。
セーブポイント
セーブポイントの有効範囲は、それが定義されたトランザクションです。メイン・トランザクション内で定義されたセーブポイントは、その自律型トランザクション内で定義されたセーブポイントとは無関係です。実際、メイン・トランザクションと自律型トランザクションのセーブポイントには、同じ名前を使用できます。
ロールバックできるのは、カレント・トランザクション内でマークされたセーブポイントまでです。自律型トランザクション内では、メイン・トランザクション内でマークされたセーブポイントまではロールバックできません。メイン・トランザクションのセーブポイントまでロールバックするには、自律型ルーチンを抜けてメイン・トランザクションを再開する必要があります。
メイン・トランザクション内では、自律型トランザクションを開始する前にマークされたセーブポイントまでロールバックしても、自律型トランザクションはロールバックされません。自律型トランザクションは、メイン・トランザクションからは完全に独立していることに注意してください。
自律型トランザクションでのエラーの回避
一般的なエラーを回避するには、次のことに注意してください。
-
メイン・トランザクションが保持するリソースに、自律型トランザクションがアクセスしようとすると、デッドロックが発生することがあります。この場合は、データベースによって自律型トランザクションで例外が呼び出され、例外が未処理になった場合、自律型トランザクションはロールバックします。
-
データベース初期化パラメータ
TRANSACTIONS
は、同時トランザクションの最大数を指定します。自律型トランザクションはメイン・トランザクションと同時に実行されるため、この最大数を超える場合があります。 -
コミットまたはロールバックせずにアクティブな自律型トランザクションを終了しようとすると、データベースによって例外が呼び出されます。例外が未処理になった場合、トランザクションはロールバックします。
-
自律型トランザクションがオープンされている間は、自律型ルーチン内で
PIPE
ROW
文を実行することはできません。PIPE
ROW
文を実行する前に、自律型トランザクションをクローズする必要があります。この処理は通常、PIPE
ROW
文を実行する前に自律型トランザクションをコミットまたはロールバックすることによって行います。
自律型トリガー
TCL文またはDDL文を実行する場合、トリガーは自律型である必要があります。
DDL文を実行する場合、トリガーは、システム固有の動的SQLを使用する必要があります。
関連項目:
-
トリガーの一般情報は、「PL/SQLトリガー」を参照してください
-
TCL文の一般情報は、「静的SQLの説明」を参照してください
-
DDL文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
-
システム固有の動的SQLの詳細は、「システム固有の動的SQL」を参照してください
トリガーの使用例の1つは、イベントのログを透過的に取ることです(たとえば、ある表に対するすべての挿入を、ロールバックしたものも含めてログに記録できます)。
例7-46 自律型トリガーによるINSERT文のログへの記録
この例では、EMPLOYEES
表に行が挿入されるたびに、トリガーによって同じ行がログ表に挿入されます。トリガーは自律型であるため、メイン表への変更をコミットするかどうかに関係なく、ログ表への変更をコミットできます。
DROP TABLE emp; CREATE TABLE emp AS SELECT * FROM employees; -- Log table: DROP TABLE log; CREATE TABLE log ( log_id NUMBER(6), up_date DATE, new_sal NUMBER(8,2), old_sal NUMBER(8,2) ); -- Autonomous trigger on emp table: CREATE OR REPLACE TRIGGER log_sal BEFORE UPDATE OF salary ON emp FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO log ( log_id, up_date, new_sal, old_sal ) VALUES ( :old.employee_id, SYSDATE, :new.salary, :old.salary ); COMMIT; END; / UPDATE emp SET salary = salary * 1.05 WHERE employee_id = 115; COMMIT; UPDATE emp SET salary = salary * 1.05 WHERE employee_id = 116; ROLLBACK; -- Show that both committed and rolled-back updates -- add rows to log table SELECT * FROM log WHERE log_id = 115 OR log_id = 116;
結果:
LOG_ID UP_DATE NEW_SAL OLD_SAL ---------- --------- ---------- ---------- 115 02-OCT-12 3255 3100 116 02-OCT-12 3045 2900 2 rows selected.
例7-47 自律型トリガーによるDDLに対するシステム固有の動的SQLの使用
この例では、自律型トリガーでシステム固有の動的SQL(EXECUTE
IMMEDIATE
文)を使用し、行が表log
に挿入された後で一時表を削除しています。
DROP TABLE temp; CREATE TABLE temp ( temp_id NUMBER(6), up_date DATE ); CREATE OR REPLACE TRIGGER drop_temp_table AFTER INSERT ON log DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN EXECUTE IMMEDIATE 'DROP TABLE temp'; COMMIT; END; / -- Show how trigger works SELECT * FROM temp;
結果:
no rows selected INSERT INTO log (log_id, up_date, new_sal, old_sal) VALUES (999, SYSDATE, 5000, 4500); 1 row created. SELECT * FROM temp;
結果:
SELECT * FROM temp * ERROR at line 1: ORA-00942: table or view does not exist
SQLからの自律型ファンクションの起動
SQL文から呼び出されるファンクションは、副作用を制御するための規則に従う必要があります。
定義上は、自立型ルーチンによってデータベース状態の読取りおよび書込みは行われません(つまり、データベース表に対する問合せや変更が行われません)。
関連項目:
詳細は、「サブプログラムの副作用」を参照
例7-48 自律型ファンクションの起動
パッケージ・ファンクションlog_msg
は自律型です。ファンクションが起動されると、データベース状態の書込み(データベース表の変更)禁止の規則に違反することなく、そのファンクションによってデータベース表debug_output
にメッセージが挿入されます。
DROP TABLE debug_output; CREATE TABLE debug_output (message VARCHAR2(200)); CREATE OR REPLACE PACKAGE debugging AUTHID DEFINER AS FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2; END debugging; / CREATE OR REPLACE PACKAGE BODY debugging AS FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO debug_output (message) VALUES (msg); COMMIT; RETURN msg; END; END debugging; / -- Invoke package function from query DECLARE my_emp_id NUMBER(6); my_last_name VARCHAR2(25); my_count NUMBER; BEGIN my_emp_id := 120; SELECT debugging.log_msg(last_name) INTO my_last_name FROM employees WHERE employee_id = my_emp_id; /* Even if you roll back in this scope, the insert into 'debug_output' remains committed, because it is part of an autonomous transaction. */ ROLLBACK; END; /