Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Verschachtelte gespeicherte Prozeduren mit TRY CATCH ROLLBACK-Muster?

Dies ist unsere Vorlage (Fehlerprotokollierung entfernt)

Dies wurde entwickelt, um

zu handhaben

Erläuterungen:

  • Alle TXN-Beginn und Commit/Rollbacks müssen gepaart werden, sodass @@TRANCOUNT ist beim Ein- und Ausstieg gleich

  • Abweichungen von @@TRANCOUNT Fehler 266 verursachen, weil

    • BEGIN TRAN erhöht @@TRANCOUNT

    • COMMIT dekrementiert @@TRANCOUNT

    • ROLLBACK gibt @@TRANCOUNT zurück auf Null

  • Sie können @@TRANCOUNT nicht verringern für den aktuellen Geltungsbereich
    Das ist, was Sie denken, die "innere Transaktion"

  • SET XACT_ABORT ON unterdrückt den Fehler 266, der durch einen nicht übereinstimmenden @@TRANCOUNT verursacht wird
    Und befasst sich auch mit Problemen wie diesem "SQL Server Transaction Timeout" auf dba.se

  • Dies ermöglicht clientseitige TXNs (wie LINQ). Eine einzelne gespeicherte Prozedur kann Teil einer verteilten oder XA-Transaktion sein oder einfach eine im Clientcode initiierte (z. B. .net TransactionScope)

Verwendung:

  • Jede gespeicherte Prozedur muss der gleichen Vorlage entsprechen

Zusammenfassung

  • Erstellen Sie also nicht mehr TXNs als Sie benötigen

Der Code

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

Hinweise:

  • Die Rollback-Prüfung ist aufgrund von SET XACT_ABORT ON eigentlich überflüssig . Allerdings fühle ich mich damit besser, sieht ohne seltsam aus und ermöglicht Situationen, in denen Sie es nicht tragen möchten

  • Remus Rusanu hat eine ähnliche Shell die Speicherpunkte verwendet. Ich bevorzuge einen atomaren DB-Aufruf und verwende keine Teilaktualisierungen wie in ihrem Artikel