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, если транзакция была классифицирована как незафиксированная транзакция.
Взаимные блокировки всегда приводят к некомпетентным транзакциям. Фактически, в случае взаимоблокировки к моменту обнаружения исключения взаимоблокировки транзакция уже откатилась как жертва взаимоблокировки.