現在のトランザクションへのアクセス
適用対象: SQL Server
SQL Server で実行されている共通言語ランタイム (CLR) コードが入力された時点でトランザクションがアクティブな場合、トランザクションは System.Transactions.Transaction クラスを介して公開されます。 Transaction.Current プロパティは、現在のトランザクションにアクセスするために使用されます。 ほとんどの場合、トランザクションに明示的にアクセスする必要はありません。 データベース接続の場合、ADO.NET は、Connection.Open メソッドが呼び出されたときに Transaction.Current を自動的にチェックし、そのトランザクションに透過的に接続を参加させます (Enlist キーワードが接続文字列で false に設定されていない場合)。
次のシナリオでは、 Transaction オブジェクトを直接使用できます。
自動参加が行われないリソースや、何かの理由で初期化中に参加しなかったリソースを参加させる場合。
リソースを明示的にトランザクションに参加させる場合。
ストアド プロシージャまたは関数内から外部トランザクションを終了させる場合。 この場合は、TransactionScope を使用します。 たとえば、次のコードでは、現在のトランザクションがロールバックされます。
using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }
以下に、外部トランザクションを取り消す別の方法を説明します。
外部トランザクションのキャンセル
外部トランザクションは、次の方法でマネージド プロシージャまたは関数からキャンセルできます。
マネージド プロシージャまたは関数は、出力パラメーターを使用して値を返すことができます。 呼び出し元の Transact-SQL プロシージャは、戻り値を確認し、必要に応じて、
ROLLBACK TRANSACTION を実行できます。マネージド プロシージャまたは関数は、カスタムの例外をスローできます。 Transact-SQL プロシージャを呼び出すと、try/catch ブロック内のマネージド プロシージャまたは関数によってスローされた例外をキャッチし、
ROLLBACK TRANSACTION を実行できます。マネージド プロシージャまたは関数は、特定の条件が満たされた場合に Transaction.Rollback メソッドを呼び出すことによって、現在のトランザクションを取り消すことができます。
マネージド プロシージャまたは関数内で呼び出されると、 Transaction.Rollback メソッドはあいまいなエラー メッセージを含む例外をスローし、try/catch ブロックにラップできます。 エラー メッセージは次のようになります。
Msg 3994, Level 16, State 1, Procedure uspRollbackFromProc, Line 0
Transaction is not allowed to roll back inside a user defined routine, trigger or aggregate because the transaction is not started in that CLR level. Change application logic to enforce strict transaction nesting.
この例外は想定されるものであり、コードの実行を継続するには try/catch ブロックが必要です。 try/catch ブロックがないと、呼び出し元の Transact-SQL プロシージャに例外が直ちにスローされ、マネージド コードの実行が完了します。 マネージド コードが実行を終了すると、別の例外が発生します。
Msg 3991, Level 16, State 1, Procedure uspRollbackFromProc, Line 1
The context transaction which was active before entering user defined routine, trigger or aggregate " uspRollbackFromProc " has been ended inside of it, which is not allowed. Change application logic to enforce strict transaction nesting. The statement has been terminated.
この例外も想定されており、実行を続行するには、トリガーを起動するアクションを実行する Transact-SQL ステートメントの周囲に try/catch ブロックが必要です。 この 2 つの例外がスローされますが、トランザクションはロールバックされ、変更はコミットされません。
例
Transaction.Rollback メソッドを使用して、マネージド プロシージャからロールバックされるトランザクションの例を次に示します。 マネージド コードの Transaction.Rollback メソッドの周囲にある try/catch ブロックに注目してください。 Transact-SQL スクリプトは、アセンブリとマネージド ストアド プロシージャを作成します。 EXEC uspRollbackFromProc ステートメントは try/catch ブロックにラップされるので、マネージド プロシージャの実行が完了したときにスローされる例外がキャッチされます。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Transactions;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void uspRollbackFromProc()
{
using (SqlConnection connection = new SqlConnection(@"context connection=true"))
{
// Open the connection.
connection.Open();
bool successCondition = true;
// Success condition is met.
if (successCondition)
{
SqlContext.Pipe.Send("Success condition met in procedure.");
// Perform other actions here.
}
// Success condition is not met, the transaction will be rolled back.
else
{
SqlContext.Pipe.Send("Success condition not met in managed procedure. Transaction rolling back...");
try
{
// Get the current transaction and roll it back.
Transaction trans = Transaction.Current;
trans.Rollback();
}
catch (SqlException ex)
{
// Catch the expected exception.
// This allows the connection to close correctly.
}
}
// Close the connection.
connection.Close();
}
}
};
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Transactions
Partial Public Class StoredProcedures
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub uspRollbackFromProc ()
Using connection As New SqlConnection("context connection=true")
' Open the connection.
connection.Open()
Dim successCondition As Boolean
successCondition = False
' Success condition is met.
If successCondition Then
SqlContext.Pipe.Send("Success condition met in procedure.")
' Success condition is not met, the transaction will be rolled back.
Else
SqlContext.Pipe.Send("Success condition not met in managed procedure. Transaction rolling back...")
Try
' Get the current transaction and roll it back.
Dim trans As Transaction
trans = Transaction.Current
trans.Rollback()
Catch ex As SqlException
' Catch the exception instead of throwing it.
' This allows the connection to close correctly.
End Try
End If
' Close the connection.
connection.Close()
End Using
End Sub
End Class
Transact-SQL
--Register assembly.
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll'
Go
CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc
Go
-- Execute procedure.
BEGIN TRY
BEGIN TRANSACTION
-- Perform other actions.
Exec uspRollbackFromProc
-- Perform other actions.
PRINT N'Commiting transaction...'
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNum, ERROR_MESSAGE() AS ErrorMessage
PRINT N'Exception thrown, rolling back transaction.'
ROLLBACK TRANSACTION
PRINT N'Transaction rolled back.'
END CATCH
Go
-- Clean up.
DROP Procedure uspRollbackFromProc;
Go
DROP ASSEMBLY TestProcs;
Go