Трансакція та Try-catch у роботі SQL Server


9

У нас є операції DML на кожному кроці завдання SQL Server. Для того, щоб забезпечити оновлення / вставка буде відкат в разі що - щось піде не так, я завернула зміни даних про кожному кроці в TRY CATCHі TRANSACTIONблоків:

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

Чи гарантує це, що маніпуляції з даними будуть скасовані у разі помилок? Або слід враховувати інші міркування?

Чи був би кращий спосіб зробити це (використовуючи конфігурації тощо)?

Дякую.

Відповіді:


7

Я б скоріше порекомендував такий зразок, як обраний з обробки обміну винятком та вкладених транзакцій :

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

Цей зразок перевіряє XACT_STATE()вхідний блок для захисту від нерозбірливих транзакцій :

Непередавані транзакції та XACT_STATE
Якщо помилка, сформована в блоці TRY, призводить до визнання недійсним стану поточної транзакції, транзакція класифікується як транзакція, що не перебуває у стані розслідування. Помилка, яка зазвичай закінчує транзакцію поза блоком TRY, призводить до того, що транзакція переходить у нерозбірливий стан, коли помилка виникає всередині блоку TRY. Нездійсненна транзакція може виконувати лише операції з читання або ПЕРЕГЛЯДУВАННЯ ПОВЕРНЕННЯ. Транзакція не може виконати жодних операторів Transact-SQL, які б генерували операцію запису або ЗВ'ЯЗУЮТЬ ПЕРЕКЛАД. Функція XACT_STATE повертає значення -1, якщо транзакція була класифікована як непередавана транзакція. Коли пакет закінчується, Database Engine скасовує будь-які активні нерозбірливі транзакції. Якщо жодного повідомлення про помилку не було надіслано, коли транзакція перейшла в нерозбірливий стан, коли пакет закінчується, клієнтській програмі буде надіслано повідомлення про помилку. Це вказує на те, що невмируща транзакція була виявлена ​​та повернута назад.

Ваш код перевіряється @@TRANCOUNTв місцях, де його не може бути 0, він використовує суміш інформаційних повідомлень PRINT та набір результатів SELECT для успішного спілкування, він не обробляє помилки, які підлягають відшкодуванню. В ідеалі винятки повинні поширюватися на клієнта, в цьому випадку на роботу з агентом (тобто ваш улов повинен повторно збільшитися).


Дякуємо за вашу корисну відповідь та фантастичний веб-сайт! Однак мені цікаво, чи все-таки я можу використовувати цей шаблон із простим оператором DML (не збереженим процесом)? Чи потрібно також зберігати транзакцію, як показано нижче? (У мене немає програми, яку потрібно використовувати в магазині): збережіть транзакцію usp_my_procedure_name;
Sky

2

Те, що у вас є, мені добре виглядає. Я б запропонував зробити щось із інформацією, звичайно, після того, як ви скасуєте транзакцію, наприклад, запишіть її в журнал.


1
Дякуємо за вашу відповідь, чи не могли б ви дати нам підказку, як записати його до журналу?
Sky

3
Якщо ви хочете записати помилки або дані в таблицю журналів, то перед тим, як зробити відкат, скопіюйте потрібні дані в змінну таблиці (Важливо, щоб ви використовували змінну таблиці. Таблиця тимчасових даних буде повернута назад). відкат, а потім вставити дані із змінної таблиці в таблицю журналу.
HLGEM
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.