Aninhando transações

Transações explícitas podem ser aninhadas. Isso serve basicamente para dar suporte a transações em procedimentos armazenados que possam ser chamados de um processo já presente em uma transação ou de processos que não tenham nenhuma transação ativa.

O exemplo a seguir mostra o uso planejado de transações aninhadas. O procedimento TransProc obriga sua transação independentemente do modo de transação de qualquer processo que o execute. Se TransProc for chamado quando uma transação estiver ativa, a transação aninhada em TransProc será amplamente ignorada e suas instruções INSERT serão confirmadas ou revertidas com base na ação final tomada para a transação externa. Se TransProc for executado por um processo que não tenha uma transação pendente, o COMMIT TRANSACTION ao término do procedimento confirmará efetivamente as instruções INSERT.

SET QUOTED_IDENTIFIER OFF;
GO
SET NOCOUNT OFF;
GO
USE AdventureWorks2008R2;
GO
CREATE TABLE TestTrans(Cola INT PRIMARY KEY,
               Colb CHAR(3) NOT NULL);
GO
CREATE PROCEDURE TransProc @PriKey INT, @CharCol CHAR(3) AS
BEGIN TRANSACTION InProc
INSERT INTO TestTrans VALUES (@PriKey, @CharCol)
INSERT INTO TestTrans VALUES (@PriKey + 1, @CharCol)
COMMIT TRANSACTION InProc;
GO
/* Start a transaction and execute TransProc. */
BEGIN TRANSACTION OutOfProc;
GO
EXEC TransProc 1, 'aaa';
GO
/* Roll back the outer transaction, this will
   roll back TransProc's nested transaction. */
ROLLBACK TRANSACTION OutOfProc;
GO
EXECUTE TransProc 3,'bbb';
GO
/* The following SELECT statement shows only rows 3 and 4 are 
   still in the table. This indicates that the commit
   of the inner transaction from the first EXECUTE statement of
   TransProc was overridden by the subsequent rollback. */
SELECT * FROM TestTrans;
GO

A confirmação de transações internas é ignorada pelo Mecanismo de banco de dados do SQL Server. A transação é confirmada ou revertida com base na ação tomada no término da transação mais externa. Se a transação externa for confirmada, as transações aninhadas internas também serão confirmadas. Se a transação externa for revertida, então todas as transações internas também serão revertidas, sem considerar se as transações internas estavam individualmente confirmadas ou não.

Cada chamada para COMMIT TRANSACTION ou COMMIT WORK se aplica a última BEGIN TRANSACTION executada. Se as instruções de BEGIN TRANSACTION forem aninhadas, então uma instrução COMMIT só se aplicará à última transação aninhada que é a transação interna. Até mesmo se uma instrução COMMIT TRANSACTION transaction_name em uma transação aninhada recorrer ao nome de transação da transação externa, a confirmação só se aplicará à transação interna.

Não é válido para o parâmetro transaction_name de uma instrução ROLLBACK TRANSACTION referir-se às transações internas de um conjunto de transações aninhadas nomeadas. transaction_name só podem se referir ao nome de transação da transação externa. Se uma instrução de ROLLBACK TRANSACTION transaction_name que usa o nome da transação externa for executada em qualquer nível de um conjunto de transações aninhadas, todas as transações aninhadas serão revertidas. Se uma instrução ROLLBACK WORK ou ROLLBACK TRANSACTION sem um parâmetro transaction_name for executada em qualquer nível de um conjunto de transações aninhadas, todas as transações aninhadas serão revertidas, inclusive a transação externa.

A função @@TRANCOUNT registra o nível de aninhamento da atual da transação. Cada instrução BEGIN TRANSACTION incrementa @@TRANCOUNT a um. Cada instrução COMMIT TRANSACTION ou COMMIT WORK diminui @@TRANCOUNT para um. Uma instrução ROLLBACK WORK ou ROLLBACK TRANSACTION que não tem um nome de transação reverte todas as transações aninhadas e diminui @@TRANCOUNT para 0. Uma instrução ROLLBACK TRANSACTION que usa o nome de transação da transação externa em um conjunto de transações aninhadas reverte todas as transações aninhadas e diminui @@TRANCOUNT para 0. Quando não tiver certeza de que já está em uma transação, selecione SELECT @@TRANCOUNT para determinar se é um ou mais. Se @@TRANCOUNT for 0, você não está em uma transação.