Acessar a transação atual
Aplica-se: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 será 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, ADO.NET verifica Transaction.Current
automaticamente quando o método Connection.Open
é chamado e insta de forma transparente a conexão nessa transação (a menos que a palavra-chave Enlist
seja 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 a inscrição automática ou que, por algum motivo, não tenha sido inscrito durante a inicialização.
Se você desejar inscrever um recurso explicitamente na transação.
Se você quiser finalizar a transação externa de dentro do seu procedimento armazenado ou função. Nesse caso, use 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 em uma função ou em um procedimento gerenciado das seguintes maneiras:
A função ou o procedimento gerenciado 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
.A função ou o procedimento gerenciado pode gerar uma exceção personalizada. O procedimento de Transact-SQL de chamada pode capturar a exceção gerada pelo procedimento gerenciado ou função em um bloco try/catch e executar
ROLLBACK TRANSACTION
.O procedimento ou função gerenciada 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 ou função gerenciada, ele gera 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 Transact-SQL de chamada e a execução do código gerenciado é concluída. Quando o código gerenciado concluir a execução, outra exceção será 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 em torno da instrução Transact-SQL que executa a ação que aciona o gatilho. Apesar das duas exceções geradas, 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 sendo revertida de um procedimento gerenciado usando o método Transaction.Rollback
. Observe o bloco try/catch em torno 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, de modo que a exceção gerada quando o procedimento gerenciado conclui a execução é 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 no Transact-SQL
Registre o assembly.
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll'; GO CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc; GO
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
Limpe seu ambiente.
DROP PROCEDURE uspRollbackFromProc; GO DROP ASSEMBLY TestProcs; GO