Este é o nosso modelo (registro de erros removido)
Este é projetado para lidar
- Artigo de Paul Randal "Nenhuma transação aninhada no SQL Server"
- Erro 266
- Acionar reversões
Explicações:
-
todos os TXN begin e commit/rollbacks devem ser emparelhados para que@@TRANCOUNT
é o mesmo na entrada e na saída
-
incompatibilidades de@@TRANCOUNT
causar erro 266 porque
-
BEGIN TRAN
incrementa@@TRANCOUNT
-
COMMIT
decrementa@@TRANCOUNT
-
ROLLBACK
retorna@@TRANCOUNT
para zero
-
-
Você não pode diminuir@@TRANCOUNT
para o escopo atual
Isso é o que você acha que é a "transação interna"
-
SET XACT_ABORT ON
suprime o erro 266 causado por@@TRANCOUNT
incompatível
E também lida com problemas como este "Tempo limite de transação do SQL Server" em dba.se
-
Isso permite TXNs do lado do cliente (como LINQ) Um único procedimento armazenado pode fazer parte de uma transação distribuída ou XA, ou simplesmente uma iniciada no código do cliente (digamos, .net TransactionScope)
Uso:
- Cada proc armazenado deve estar em conformidade com o mesmo modelo
Resumo
- Portanto, não crie mais TXNs do que você precisa
O código
CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE @starttrancount int
BEGIN TRY
SELECT @starttrancount = @@TRANCOUNT
IF @starttrancount = 0
BEGIN TRANSACTION
[...Perform work, call nested procedures...]
IF @starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND @starttrancount = 0
ROLLBACK TRANSACTION;
THROW;
--before SQL Server 2012 use
--RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO
Observações:
-
A verificação de reversão é realmente redundante por causa deSET XACT_ABORT ON
. No entanto, isso me faz sentir melhor, parece estranho sem e permite situações em que você não quer
-
Remus Rusanu tem um shell semelhante que usa pontos de salvamento. Eu prefiro uma chamada de banco de dados atômica e não uso atualizações parciais como o artigo deles