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

Die Transaktionsanzahl nach EXECUTE weist auf eine nicht übereinstimmende Anzahl von BEGIN- und COMMIT-Anweisungen hin. Vorheriger Zählerstand =1, aktueller Zählerstand =0

Wenn Sie einen TRY/CATCH-Block haben, ist die wahrscheinliche Ursache, dass Sie eine Transaktionsabbruch-Ausnahme abfangen und fortfahren. Im CATCH-Block müssen Sie immer den XACT_STATE() und entsprechende abgebrochene und nicht festschreibbare (zum Scheitern verurteilte) Transaktionen handhaben. Wenn Ihr Anrufer eine Transaktion startet und der Angerufene beispielsweise einen Deadlock erreicht (der die Transaktion abbrach), wie wird der Angerufene dem Anrufer mitteilen, dass die Transaktion abgebrochen wurde und nicht wie gewohnt fortgesetzt werden soll? Der einzig praktikable Weg besteht darin, eine Ausnahme erneut auszulösen und den Aufrufer zu zwingen, die Situation zu handhaben. Wenn Sie stillschweigend eine abgebrochene Transaktion schlucken und der Anrufer weiterhin davon ausgeht, dass er sich noch in der ursprünglichen Transaktion befindet, kann nur Chaos sicherstellen (und der Fehler, den Sie erhalten, ist die Art und Weise, wie die Engine versucht, sich selbst zu schützen).

Ich empfehle Ihnen, Ausnahmebehandlung und verschachtelte Transaktionen die ein Muster zeigt, das mit verschachtelten Transaktionen und Ausnahmen verwendet werden kann:

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch
end
go