TSQL - ошибка при запуске процедуры внутри транзакции, когда процедура включает транзакцию - PullRequest
0 голосов
/ 25 октября 2019

В хранимой процедуре у меня есть блок try catch с транзакцией, которая будет зафиксирована, если управление никогда не перейдет к catch, в противном случае произойдет откат, если возникнет ошибка, и управление перейдет к блоку catch.

I 'Я запускаю эту хранимую процедуру из транзакции, как показано в следующем примере:

 CREATE PROCEDURE sp_test
 AS
 BEGIN
     BEGIN TRY
         BEGIN TRAN
             DECLARE @var INT = 1
             IF @var <> 2 
                 BEGIN
                     RAISERROR('error', 16,1)
                 END
         COMMIT
     END TRY
     BEGIN CATCH
         ROLLBACK
         PRINT 'Rolled back'
     END CATCH
 END


 BEGIN TRAN

 EXEC sp_test

Когда я запускаю это, я вижу ошибку

Сообщение 266, уровень 16, Состояние 2, Процедура sp_test, Строка 0 [Стартовая Строка 7]
Количество транзакций после EXECUTE указывает на несовпадающее количество операторов BEGIN и COMMIT. Предыдущий счет = 1, текущий счет = 0.

Но я не понимаю, почему.

Я запускаю транзакцию вне хранимой процедуры. Я тогда иду в SP и начинаю другую транзакцию. Как только управление переходит к блоку перехвата, обе транзакции необходимо откатить, поэтому количество транзакций должно быть равно 0.

Очевидно, в моем понимании есть пробел.

1 Ответ

1 голос
/ 25 октября 2019

Это поведение является намеренным. Всякий раз, когда транзакция запускается, переменная сеанса @@ TRANCOUNT увеличивается на единицу, а когда транзакция фиксируется, она уменьшается на единицу. Однако, когда транзакция откатывается, она откатывает все вложенные транзакции. Таким образом, в вашем случае откат в вашем улове откатит 2 вложенные транзакции, и @@ TRANCOUNT станет 0. Это приведет к тому, что вызывающий вызов выдаст исключение подсчета несовпадений транзакций.

Чтобы избежать этой проблемы, вы можетеотметьте @@ TRANCOUNT в вашем SP и начинайте новую транзакцию только когда она равна 0 и устанавливайте флаг (локальная переменная), чтобы указать это, например, @ new_tarn = 1. Тогда вы фиксируете или откатываете только когда @ new_tran = 1.

...