Accesso alla transazione corrente

Si applica a: SQL Server

Se una transazione è attiva nel punto in cui viene immesso il codice CLR (Common Language Runtime) in esecuzione in SQL Server, la transazione viene esposta tramite la classe System.Transactions.Transaction . La proprietà Transaction.Current viene utilizzata per accedere alla transazione corrente. Nella maggior parte dei casi non è necessario accedere in modo esplicito alla transazione. Per le connessioni al database, ADO.NET controlla automaticamente Transaction.Current quando viene chiamato il metodo Connection.Open e integra in modo trasparente la connessione in tale transazione ,a meno che la parola chiave Enlist non sia impostata su false nella stringa di connessione.

È possibile usare l'oggetto Transaction direttamente negli scenari seguenti:

  • Se si desidera integrare una risorsa che non esegue l'integrazione automatica o che per qualche motivo non è stata integrata durante l'inizializzazione.

  • Se si desidera integrare in modo esplicito una risorsa nella transazione.

  • Se si desidera terminare la transazione esterna dalla stored procedure o dalla funzione. In questo caso, utilizzare TransactionScope. Nel codice seguente, ad esempio, viene eseguito il rollback della transazione corrente:

    using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }  
    

Nella parte restante di questo argomento vengono descritte altre modalità di annullamento di una transazione esterna.

Annullamento di una transazione esterna

È possibile annullare le transazioni esterne da una funzione o procedura gestita nelle modalità seguenti:

  • La funzione o procedura gestita può restituire un valore utilizzando un parametro di output. La routine Transact-SQL chiamante può controllare il valore restituito e, se appropriato, eseguire ROLLBACK TRANSACTION.

  • La funzione o procedura gestita può generare un'eccezione personalizzata. La routine Transact-SQL chiamante può intercettare l'eccezione generata dalla routine o dalla funzione gestita in un blocco try/catch ed eseguire ROLLBACK TRANSACTION.

  • La routine o la funzione gestita può annullare la transazione corrente chiamando il metodo Transaction.Rollback se viene soddisfatta una determinata condizione.

Quando viene chiamato all'interno di una routine o di una funzione gestita, il metodo Transaction.Rollback genera un'eccezione con un messaggio di errore ambiguo e può essere eseguito il wrapping in un blocco try/catch. Il messaggio di errore è simile al seguente:

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.  

Questa eccezione è prevista e il blocco try/catch è necessario per continuare a eseguire il codice. Senza il blocco try/catch, l'eccezione verrà generata immediatamente alla routine Transact-SQL chiamante e l'esecuzione del codice gestito verrà completata. Al termine dell'esecuzione del codice gestito, viene generata un'altra eccezione:

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.  

Questa eccezione è prevista e, per continuare l'esecuzione, è necessario disporre di un blocco try/catch intorno all'istruzione Transact-SQL che esegue l'azione che attiva il trigger. Nonostante le due eccezioni generate, viene eseguito il rollback della transazione e le modifiche non vengono sottoposte a commit.

Esempio

Di seguito è riportato un esempio di transazione di cui viene eseguito il rollback da una routine gestita usando il metodo Transaction.Rollback . Si noti il blocco try/catch intorno al metodo Transaction.Rollback nel codice gestito. Lo script Transact-SQL crea un assembly e una stored procedure gestita. Tenere presente che l'istruzione EXEC uspRollbackFromProc viene sottoposta a wrapping in un blocco try/catch, in modo che l'eccezione generata quando la routine gestita completa l'esecuzione viene intercettata.

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  

Vedi anche

Integrazione con CLR e transazioni