Om du får felmeddelande 3902, nivå 16, som lyder "The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION", beror det förmodligen på att du har en bortkommen COMMIT
uttalande.
Du kan få detta på grund av att du implementerar felhantering och glömmer att du redan har genomfört eller återställt transaktionen någon annanstans i din kod.
Exempel på fel
Här är ett enkelt exempel för att visa felet:
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Resultat:
(7 rows affected) Msg 3902, Level 16, State 1, Line 2 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Detta inträffar om din SET IMPLICIT_TRANSACTIONS
är OFF
. Se nedan för vad som händer när SET IMPLICIT_TRANSACTIONS
är ON
.
Exempel på fel på grund av felhantering
Du kan få detta på grund av att du implementerar felhantering och glömmer att du redan har genomfört eller återställt transaktionen någon annanstans i din kod.
Till exempel:
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;
Resultat:
(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.
I det här fallet hade jag redan COMMIT TRANSACTION
i TRY
blockera. Så när den andra COMMIT TRANSACTION
påträffades, hade transaktionen redan genomförts.
Vi skulle se detsamma även om transaktionen hade stött på ett fel och återställts. En återställning kommer att avsluta transaktionen och därför ingen ytterligare COMMIT
uttalanden krävs.
Så för att åtgärda det här problemet skulle vi helt enkelt ta bort den sista COMMIT TRANSACTION
, och transaktionskoden skulle se ut så här:
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
Implicita transaktioner
Om du har aktiverat implicita transaktioner kan du få andra resultat än det första exemplet.
Om vi ställer in IMPLICIT_TRANSACTIONS
till ON
, här är vad vi får:
SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Resultat:
+---------------------------------+----------------+ | 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)
Inget fel uppstår.
Detta beror på att vissa T-SQL-satser automatiskt startar en transaktion när de körs. Det är som om de föregåtts av en osynlig BEGIN TRANSACTION
uttalande.
När IMPLICIT_TRANSACTIONS
är OFF
, dessa uttalanden begås automatiskt. Det är som om de efterträds av en osynlig COMMIT TRANSACTION
påstående. I det här scenariot är transaktionen i autocommit-läge.
När IMPLICIT_TRANSACTIONS
är ON
, det finns ingen osynlig COMMIT TRANSACTION
påstående. Dessa uttalanden startas fortfarande av en osynlig BEGIN TRANSACTION
, men de måste avslutas explicit.
En implicit transaktion förblir pågående tills den antingen explicit begåtts eller explicit återställs.
Därför, i det här exemplet, vår herrelösa COMMIT TRANSACTION
uttalande behövdes faktiskt för att avsluta den implicita transaktionen.