Partilhar via


Acesse a transação atual

Aplica-se a:SQL Server

Se uma transação estiver ativa no ponto em que o código CLR (Common Language Runtime) em execução no SQL Server for inserido, a transação será exposta por meio da classe System.Transactions.Transaction. A propriedade Transaction.Current é usada para acessar a transação atual. Na maioria dos casos, não é necessário acessar a transação explicitamente. Para conexões de banco de dados, o ADO.NET verifica Transaction.Current automaticamente quando o método Connection.Open é chamado e inscreve de forma transparente a conexão nessa transação (a menos que a palavra-chave Enlist esteja definida como false na cadeia de conexão).

Talvez você queira usar o objeto Transaction diretamente nos seguintes cenários:

  • Se você quiser inscrever um recurso que não faça alistamento automático ou que, por algum motivo, não tenha sido alistado durante a inicialização.

  • Se você quiser inscrever explicitamente um recurso na transação.

  • Se você quiser encerrar a transação externa de dentro do seu procedimento armazenado ou função. Nesse caso, você usa TransactionScope. Por exemplo, o código a seguir reverte a transação atual:

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

O restante deste artigo descreve outras maneiras de cancelar uma transação externa.

Cancelar uma transação externa

Você pode cancelar transações externas de um procedimento ou função gerenciada das seguintes maneiras:

  • O procedimento ou função gerenciada pode retornar um valor usando um parâmetro de saída. O procedimento de Transact-SQL de chamada pode verificar o valor retornado e, se apropriado, executar ROLLBACK TRANSACTION.

  • O procedimento ou função gerenciada pode gerar uma exceção personalizada. O procedimento de chamada Transact-SQL pode capturar a exceção lançada pelo procedimento gerenciado ou função em um bloco try/catch e executáROLLBACK TRANSACTION.

  • O procedimento gerenciado ou função pode cancelar a transação atual chamando o método Transaction.Rollback se uma determinada condição for atendida.

Quando o método Transaction.Rollback é chamado dentro de um procedimento gerenciado ou função, ele lança uma exceção com uma mensagem de erro ambígua e pode ser encapsulado em um bloco try/catch. A mensagem de erro é semelhante à seguinte saída:

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.

Essa exceção é esperada e o bloco try/catch é necessário para que a execução do código continue. Sem o bloco try/catch, a exceção é imediatamente lançada para o procedimento de chamada Transact-SQL e a execução do código gerenciado é concluída. Quando o código gerenciado termina a execução, outra exceção é gerada:

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.

Essa exceção também é esperada e, para que a execução continue, você deve ter um bloco try/catch ao redor da instrução Transact-SQL que executa a ação que dispara o gatilho. Apesar das duas exceções lançadas, a transação é revertida e as alterações não são confirmadas.

Exemplo

O código a seguir é um exemplo de uma transação que está sendo revertida de um procedimento gerenciado usando o método Transaction.Rollback. Observe o bloco try/catch ao redor do método Transaction.Rollback no código gerenciado. O script Transact-SQL cria um assembly e um procedimento armazenado gerenciado. A instrução EXEC uspRollbackFromProc é encapsulada em um bloco try/catch, para que a exceção lançada quando o procedimento gerenciado concluir a execução seja capturada.

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();
   }
}
};

Registrar e executar o assembly em Transact-SQL

  1. Registre a montagem.

    CREATE ASSEMBLY TestProcs
        FROM 'C:\Programming\TestProcs.dll';
    GO
    
    CREATE PROCEDURE uspRollbackFromProc
    AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc;
    GO
    
  2. Execute o procedimento.

    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. Limpe o seu ambiente.

    DROP PROCEDURE uspRollbackFromProc;
    GO
    
    DROP ASSEMBLY TestProcs;
    GO