Ако получавате съобщение за грешка Msg 3902, ниво 16, което гласи „Заявката COMMIT TRANSACTION няма съответна BEGIN TRANSACTION“, това вероятно е защото имате бездомен COMMIT
изявление.
Може да получите това поради внедряване на обработка на грешки и забравяне, че вече сте ангажирали или отменили транзакцията другаде в кода си.
Пример за грешка
Ето един прост пример за демонстриране на грешката:
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Резултат:
(7 rows affected) Msg 3902, Level 16, State 1, Line 2 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Това ще се случи, ако SET IMPLICIT_TRANSACTIONS
е OFF
. Вижте по-долу какво се случва, когато SET IMPLICIT_TRANSACTIONS
е ON
.
Пример за грешка поради обработка на грешки
Може да получите това поради внедряване на обработка на грешки и забравяне, че вече сте ангажирали или отменили транзакцията другаде в кода си.
Например:
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Orders ( OrderId, OrderDate, CustomerId )
VALUES ( 5006, SYSDATETIME(), 1006 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 1, 1, 20, 25.99 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 2, 7, 120, 9.99 );
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
COMMIT TRANSACTION;
Резултат:
(1 row affected) (1 row affected) (1 row affected) Msg 3902, Level 16, State 1, Line 20 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
В този случай вече имах COMMIT TRANSACTION
в TRY
блок. Така че до момента на втората COMMIT TRANSACTION
е бил открит, транзакцията вече е била извършена.
Ще видим същото, дори ако транзакцията е срещнала грешка и е била отменена. Отмяната ще прекрати транзакцията и следователно няма повече COMMIT
са необходими изявления.
Така че, за да коригираме този проблем, просто ще премахнем последната COMMIT TRANSACTION
, а кодът на транзакцията ще изглежда така:
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Orders ( OrderId, OrderDate, CustomerId )
VALUES ( 5006, SYSDATETIME(), 1006 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 1, 1, 20, 25.99 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 2, 7, 120, 9.99 );
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
Неявни транзакции
Ако имате активирани неявни транзакции, може да получите различни резултати от първия пример.
Ако зададем IMPLICIT_TRANSACTIONS
до ON
, ето какво получаваме:
SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Резултат:
+---------------------------------+----------------+ | ProductName | ProductPrice | |---------------------------------+----------------| | Left handed screwdriver | 25.99 | | Long Weight (blue) | 14.75 | | Long Weight (green) | 11.99 | | Sledge Hammer | 33.49 | | Chainsaw | 245.00 | | Straw Dog Box | 55.99 | | Bottomless Coffee Mugs (4 Pack) | 9.99 | +---------------------------------+----------------+ (7 rows affected)
Не се появява грешка.
Това е така, защото определени T-SQL оператори автоматично стартират транзакция, когато се изпълняват. Сякаш са предшествани от невидима BEGIN TRANSACTION
изявление.
Когато IMPLICIT_TRANSACTIONS
е OFF
, тези изявления се ангажират автоматично. Сякаш са последвани от невидима COMMIT TRANSACTION
изявление. В този сценарий транзакцията е в режим на автоматично извършване.
Когато IMPLICIT_TRANSACTIONS
е ON
, няма невидима COMMIT TRANSACTION
изявление. Тези оператори все още се стартират от невидима BEGIN TRANSACTION
, но те трябва да бъдат завършени изрично.
Неявната транзакция остава в ход, докато не бъде изрично ангажирана или изрично връщана назад.
Следователно, в този пример, нашата бездомна COMMIT TRANSACTION
изявлението всъщност беше необходимо за прекратяване на имплицитната транзакция.