Transazione e Try-catch nel processo di SQL Server


9

Abbiamo operazioni DML in ogni passaggio di un processo di SQL Server. Per garantire l'aggiornamento / inserimento verrà eseguito il rollback in caso qualcosa vada storto, ho avvolto le modifiche dei dati di ogni passo in TRY CATCHe TRANSACTIONblocchi:

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

Garantisce il rollback delle manipolazioni dei dati in caso di errori? O altre considerazioni dovrebbero essere prese in considerazione?

Sarebbe un modo migliore per farlo (usando configurazioni, ecc.)?

Grazie.

Risposte:


7

Preferirei raccomandare un modello come quello della gestione delle eccezioni e delle transazioni nidificate :

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

Questo modello controlla il XACT_STATE()blocco catch per proteggersi dalle transazioni non impegnabili :

Transazioni non vincolanti e XACT_STATE
Se un errore generato in un blocco TRY provoca l'invalidazione dello stato della transazione corrente, la transazione viene classificata come transazione non impegnabile. Un errore che di solito termina una transazione al di fuori di un blocco TRY fa sì che una transazione entri in uno stato non impegnabile quando si verifica l'errore all'interno di un blocco TRY. Una transazione non vincolante può eseguire solo operazioni di lettura o TRANSAZIONE ROLLBACK. La transazione non può eseguire alcuna istruzione Transact-SQL che genererebbe un'operazione di scrittura o COMMIT TRANSACTION. La funzione XACT_STATE restituisce un valore di -1 se una transazione è stata classificata come transazione non negoziabile. Al termine di un batch, Motore di database esegue il rollback di tutte le transazioni non eseguibili attive. Se non è stato inviato alcun messaggio di errore quando la transazione è entrata in uno stato non compatibile, al termine del batch, verrà inviato un messaggio di errore all'applicazione client. Ciò indica che è stata rilevata e ripristinata una transazione non vincolante.

Il codice sta cercando @@TRANCOUNTin luoghi in cui non può essere 0, utilizza una combinazione di messaggi PRINT informativi e set di risultati SELECT per comunicare con successo, non gestisce gli errori recuperabili. Idealmente, le eccezioni dovrebbero propagarsi al client, in questo caso al lavoro dell'agente (ovvero, il pescato dovrebbe essere rilanciato).


Grazie per la tua risposta utile e sito fantastico! Tuttavia mi chiedo se posso ancora utilizzare questo modello con una semplice istruzione DML (non un proc memorizzato)? Inoltre dobbiamo salvare la transazione come di seguito? (Non ho un proc store da utilizzare): salva la transazione usp_my_procedure_name;
Sky

2

Quello che hai sembra buono per me. Suggerirei di fare qualcosa con le informazioni ovviamente dopo aver eseguito il rollback della transazione, ad esempio scriverlo in un registro.


1
Grazie per la tua risposta, potresti darmi un suggerimento su come scriverlo in un registro?
Sky

3
Se si desidera scrivere errori o dati in una tabella di registro, quindi prima di eseguire il rollback, copiare i dati desiderati in una variabile di tabella (è importante utilizzare una variabile di tabella, verrà eseguito il rollback di una tabella temporanea), quindi eseguire il rollback, quindi inserire i dati dalla variabile della tabella nella tabella di registrazione.
HLGEM,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.