入れ子構造のトランザクション
明示的なトランザクションは入れ子にすることができます。これは、トランザクション内の既存のプロセスからでもアクティブ トランザクションがないプロセスからでも呼び出せるストアド プロシージャ内のトランザクションをサポートすることを主な目的としています。
次の例は、入れ子構造のトランザクションの使用方法を示しています。プロシージャ TransProc は、プロセスのトランザクション モードに関係なくトランザクションを実行します。トランザクションがアクティブであるときに TransProc を呼び出すと、TransProc 内の入れ子になっているトランザクションは概して無視され、外側のトランザクションに対して行った最終的な操作に基づいて INSERT ステートメントがコミットまたはロールバックされます。未完了のトランザクションがないプロセスが TransProc を実行した場合は、プロシージャの最後に INSERT ステートメントが COMMIT TRANSACTION によって有効にコミットされます。
SET QUOTED_IDENTIFIER OFF;
GO
SET NOCOUNT OFF;
GO
USE AdventureWorks;
GO
CREATE TABLE TestTrans(Cola INT PRIMARY KEY,
Colb CHAR(3) NOT NULL);
GO
CREATE PROCEDURE TransProc @PriKey INT, @CharCol CHAR(3) AS
BEGIN TRANSACTION InProc
INSERT INTO TestTrans VALUES (@PriKey, @CharCol)
INSERT INTO TestTrans VALUES (@PriKey + 1, @CharCol)
COMMIT TRANSACTION InProc;
GO
/* Start a transaction and execute TransProc. */
BEGIN TRANSACTION OutOfProc;
GO
EXEC TransProc 1, 'aaa';
GO
/* Roll back the outer transaction, this will
roll back TransProc's nested transaction. */
ROLLBACK TRANSACTION OutOfProc;
GO
EXECUTE TransProc 3,'bbb';
GO
/* The following SELECT statement shows only rows 3 and 4 are
still in the table. This indicates that the commit
of the inner transaction from the first EXECUTE statement of
TransProc was overridden by the subsequent rollback. */
SELECT * FROM TestTrans;
GO
SQL Server データベース エンジンでは、入れ子の内側のトランザクションのコミットが無視されます。内側のトランザクションは、最も外側にあるトランザクションの最後に行われた操作に基づいてコミットまたはロールバックされます。外側のトランザクションがコミットされると、入れ子の内側のトランザクションもコミットされます。外側のトランザクションがロールバックされると、内側のトランザクションも、個々がコミットされたかどうかに関係なくすべてロールバックされます。
COMMIT TRANSACTION または COMMIT WORK への各呼び出しは、最後に実行された BEGIN TRANSACTION に適用されます。BEGIN TRANSACTION ステートメントが入れ子になっている場合、最後の入れ子になっているトランザクション、つまり最も内側のトランザクションだけに COMMIT ステートメントが適用されます。入れ子になったトランザクション内の COMMIT TRANSACTION transaction_name ステートメントが、外側のトランザクションの名前を参照している場合でも、コミットが適用されるのは最も内側のトランザクションだけです。
ROLLBACK TRANSACTION ステートメントの transaction_name パラメータで、入れ子構造になっている一連の名前付きトランザクションのうち、内側のトランザクションを参照するのは不正な操作です。transaction_name で参照できるのは、最も外側のトランザクションの名前のみです。入れ子構造になっている一連のトランザクションの任意のレベルで、外側のトランザクションの名前を使用して ROLLBACK TRANSACTION transaction_name ステートメントで実行すると、入れ子構造のトランザクションすべてがロールバックされます。入れ子構造になっている一連のトランザクションの任意のレベルで、transaction_name パラメータを指定せずに ROLLBACK WORK ステートメントまたは ROLLBACK TRANSACTION ステートメントを実行すると、最も外側のトランザクションを含めて、入れ子構造のトランザクションすべてがロールバックされます。
@@TRANCOUNT 関数は、現在のトランザクションの入れ子レベルを記録します。@@TRANCOUNT の値は、BEGIN TRANSACTION ステートメントが実行されるごとに 1 ずつ増加します。COMMIT TRANSACTION ステートメントまたは COMMIT WORK ステートメントが実行されると、@@TRANCOUNT が 1 ずつ減少します。ROLLBACK WORK ステートメントまたは ROLLBACK TRANSACTION ステートメントにトランザクション名を指定しないと、入れ子構造の内側のトランザクションすべてがロールバックされ、@@TRANCOUNT は 0 まで減少します。ROLLBACK TRANSACTION で、入れ子構造になっている一連のトランザクションの最も外側のトランザクションの名前を指定すると、入れ子構造の内側のトランザクションすべてがロールバックされ、@@TRANCOUNT は 0 まで減少します。トランザクションの実行中であるかどうかを確信できないときは、SELECT @@TRANCOUNT を指定して、@@TRANCOUNT が 1 以上であるかどうかを確認します。@@TRANCOUNT が 0 であれば、トランザクションの実行中ではありません。