Transakcja i Try-catch w zadaniu SQL Server

9

Mamy operacje DML na każdym etapie zadania programu SQL Server. Aby zapewnić aktualizację / wkładka zostanie wycofana w przypadku coś pójdzie nie tak, mam owinięty modyfikacji danych o każdym kroku w TRY CATCHi TRANSACTIONbloków:

BEGIN TRY
    BEGIN TRANSACTION

        [[INSERT/update statements]] ...

    IF @@TRANCOUNT > 0
    BEGIN
        COMMIT TRANSACTION
        PRINT 'Successful.'
    END

END TRY

BEGIN CATCH
    SELECT
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage

    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION
        PRINT 'Unsuccessful.'
    END
END CATCH

Czy zapewnia to wycofanie manipulacji danymi w przypadku błędu (błędów)? Czy należy wziąć pod uwagę inne względy?

Czy byłby to lepszy sposób (używając konfiguracji itp.)?

Dziękuję Ci.

Niebo
źródło

Odpowiedzi:

7

Wolałbym zalecić wzorzec taki jak ten z obsługi wyjątków i transakcji zagnieżdżonych :

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

Ten wzór sprawdza XACT_STATE()blok catch w celu zabezpieczenia przed nieprzewidzianymi transakcjami :

Niezatwierdzone transakcje i XACT_STATE
Jeśli błąd wygenerowany w bloku TRY powoduje unieważnienie stanu bieżącej transakcji, transakcja jest klasyfikowana jako transakcja niezaangażowana. Błąd, który zwykle kończy transakcję poza blokiem TRY, powoduje, że transakcja przechodzi w stan niezaangażowania, gdy błąd występuje w bloku TRY. Niezatwierdzona transakcja może wykonywać tylko operacje odczytu lub TRANSAKCJĘ ROLLBACK. Transakcja nie może wykonać żadnych instrukcji Transact-SQL, które wygenerowałyby operację zapisu lub TRANSIT TRANSMISJI. Funkcja XACT_STATE zwraca wartość -1, jeśli transakcja została zaklasyfikowana jako transakcja niezaangażowana. Po zakończeniu partii Aparat baz danych wycofuje wszelkie aktywne niezaangażowane transakcje. Jeśli komunikat o błędzie nie został wysłany, gdy transakcja weszła w stan niezaangażowania, po zakończeniu partii do aplikacji klienckiej zostanie wysłany komunikat o błędzie. Oznacza to, że wykryto i wycofano nieprzewidzianą transakcję.

Twój kod sprawdza @@TRANCOUNTw miejscach, w których nie może być równy 0, używa mieszanki informacyjnych komunikatów PRINT i zestawów wyników SELECT do komunikowania się, nie obsługuje błędów, które można naprawić. W idealnym przypadku wyjątki powinny zostać przekazane klientowi, w tym przypadku do zadania agenta (tzn. Twój haczyk powinien zostać ponownie podniesiony).

Remus Rusanu
źródło
Dziękujemy za pomocną odpowiedź i fantastyczną stronę internetową! Zastanawiam się jednak, czy nadal mogę używać tego wzorca z prostą instrukcją DML (nie przechowywanym procem)? Czy musimy również zapisać transakcję jak poniżej? (Nie mam proca sklepu do użycia): zapisz transakcję usp_my_procedure_name;
Sky
2

To, co masz, wygląda dla mnie dobrze. Sugerowałbym zrobienie czegoś z informacjami oczywiście po wycofaniu transakcji, np. Zapisanie jej w dzienniku.

datagod
źródło
1
Dzięki za odpowiedź, czy mógłbyś mi podpowiedzieć, jak zapisać to w dzienniku?
Sky
3
Jeśli chcesz zapisać błędy lub dane do tabeli dziennika, to przed cofnięciem skopiuj dane, które chcesz do zmiennej tabeli (ważne jest, aby użyć zmiennej tabeli, tabela temp zostanie wycofana). Następnie wykonaj wycofaj, a następnie wstaw dane ze zmiennej tabeli do tabeli rejestrowania.
HLGEM