Share via


現在のトランザクションへのアクセス

適用対象:SQL Server

SQL Serverで実行されている共通言語ランタイム (CLR) コードが入力された時点でトランザクションがアクティブな場合、トランザクションは System.Transactions.Transaction クラスを介して公開されます。 Transaction.Current プロパティは、現在のトランザクションにアクセスするために使用されます。 ほとんどの場合、トランザクションに明示的にアクセスする必要はありません。 データベース接続の場合、ADO.NET Connection.Open メソッドが呼び出されたときに Transaction.Current が自動的にチェックされ、そのトランザクションに透過的に接続が参加します (接続文字列で Enlist キーワード (keyword)が 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  

参照

CLR 統合とトランザクション