Condividi tramite


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 usata 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 inserisce in modo trasparente la connessione in tale transazione ( a meno che la parola chiave Enlist 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ò rilevare l'eccezione generata dalla routine gestita o dalla funzione in un blocco try/catch ed eseguire ROLLBACK TRANSACTION.

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

Quando viene chiamato all'interno di una routine gestita o di una funzione, 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 anche 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 rollback di una transazione 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 procedura gestita completa l'esecuzione viene rilevata.

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  

Vedere anche

Integrazione con CLR e transazioni