SQL Try / Catch логика с вложенными транзакциями - PullRequest
3 голосов
/ 10 декабря 2011

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

Есть идеи, где происходит несоответствие?

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 Ответ

5 голосов
/ 15 декабря 2011

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

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

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

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

...