Condividi tramite


Accedere 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 alla transazione in modo esplicito. 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 vuole integrare una risorsa che non esegue l'integrazione automatica o che per qualche motivo non è stata inserita 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. Ad esempio, il codice seguente esegue il rollback della transazione corrente:

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

Il resto di questo articolo descrive altri modi per annullare una transazione esterna.

Annullare 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 gestita o la funzione può annullare la transazione corrente chiamando il metodo Transaction.Rollback se viene soddisfatta una determinata condizione.

Quando il metodo Transaction.Rollback viene chiamato all'interno di una routine o di una funzione gestita, 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 all'output 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 viene generata immediatamente alla routine chiamante Transact-SQL e l'esecuzione del codice gestito termina. 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

Il codice seguente è un esempio di una 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. 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();
   }
}
};

Registrare ed eseguire l'assembly in Transact-SQL

  1. Registrare l'assembly.

    CREATE ASSEMBLY TestProcs
        FROM 'C:\Programming\TestProcs.dll';
    GO
    
    CREATE PROCEDURE uspRollbackFromProc
    AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc;
    GO
    
  2. Eseguire la procedura.

    BEGIN TRY
        BEGIN TRANSACTION;
    
        -- Perform other actions.
        EXECUTE 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;
        PRINT N'Transaction rolled back.';
    END CATCH
    GO
    
  3. Pulire l'ambiente.

    DROP PROCEDURE uspRollbackFromProc;
    GO
    
    DROP ASSEMBLY TestProcs;
    GO