SQL Try/Catch логика с вложенными транзакциями

Следующее sproc реализовано в соответствии с шаблоном в этой статье: Обработка исключений и вложенные транзакции. Предполагается, что этот sproc обрабатывает взаимоблокировки и вызывается другим sproc, который уже создает транзакцию. Некоторое волшебство с BEGIN/COMMIT внутренней транзакции не совпадает, потому что я получаю это исключение: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0, Насколько я понимаю, улов выполнен, @xstate = -1 верно, и вся внешняя транзакция откатывается.

Любые идеи, где происходит несоответствие?

CREATE PROCEDURE [dbo].[mysproc]
AS
BEGIN
    SET NOCOUNT ON;
    SET DEADLOCK_PRIORITY LOW;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  

    BEGIN TRY        
        DECLARE @trancount int;
        SET @trancount = @@TRANCOUNT;        
        IF (@trancount = 0)
            BEGIN TRANSACTION;
        ELSE
            SAVE TRANSACTION InnerTran;   
        --              
        -- do some work that can potentially cause a deadlock
        --
   END TRY
   BEGIN CATCH
        DECLARE @xstate int
        SELECT @xstate = XACT_STATE()

        IF (@xstate = - 1)
            ROLLBACK;
        IF (@xstate = 1 and @trancount = 0)
            ROLLBACK;
        IF (@xstate = 1 and @trancount > 0)
            ROLLBACK TRANSACTION InnerTran;
   END CATCH  
END
GO

1 ответ

Решение

Разница в том, что вы не выдвигаете исключение. В случае XACT_STATE() равен -1 в блоке перехвата (т. е. незафиксированная транзакция, как могло бы произойти из-за тупиковой ситуации). В таком случае ваша процедура будет иметь откат (она должна иметь выбор в -1, но вернется без выдачи исключения). Отсюда и несоответствие. Вы должны вызвать исключение и поймать его в вызывающей стороне.

Смотрите Uncommittable транзакции и XACT_STATE:

Если ошибка, сгенерированная в блоке TRY, приводит к тому, что состояние текущей транзакции становится недействительным, транзакция классифицируется как незафиксированная транзакция. Ошибка, которая обычно завершает транзакцию вне блока TRY, приводит к тому, что транзакция переходит в состояние uncommittable, когда ошибка происходит внутри блока TRY. Нефиксированная транзакция может выполнять только операции чтения или ROLLBACK TRANSACTION. Транзакция не может выполнить какие-либо операторы Transact-SQL, которые бы генерировали операцию записи или COMMIT TRANSACTION. Функция XACT_STATE возвращает значение -1, если транзакция была классифицирована как незафиксированная транзакция.

Взаимные блокировки всегда приводят к некомпетентным транзакциям. Фактически, в случае взаимоблокировки к моменту обнаружения исключения взаимоблокировки транзакция уже откатилась как жертва взаимоблокировки.

Другие вопросы по тегам