Jeśli otrzymujesz komunikat o błędzie 3902, poziom 16, który brzmi „Żądanie COMMIT TRANSACTION nie ma odpowiadającej BEGIN TRANSACTION”, to prawdopodobnie dlatego, że masz zabłąkany COMMIT
oświadczenie.
Może to być spowodowane wdrożeniem obsługi błędów i zapominaniem, że już zatwierdziłeś lub wycofałeś transakcję w innym miejscu kodu.
Przykład błędu
Oto prosty przykład demonstrujący błąd:
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Wynik:
(7 rows affected) Msg 3902, Level 16, State 1, Line 2 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Nastąpi to, jeśli Twój SET IMPLICIT_TRANSACTIONS
jest OFF
. Zobacz poniżej, co się stanie, gdy SET IMPLICIT_TRANSACTIONS
jest ON
.
Przykład błędu spowodowanego obsługą błędów
Może to być spowodowane wdrożeniem obsługi błędów i zapominaniem, że już zatwierdziłeś lub wycofałeś transakcję w innym miejscu kodu.
Na przykład:
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;
Wynik:
(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.
W tym przypadku miałem już COMMIT TRANSACTION
w TRY
blok. Więc do czasu drugiego COMMIT TRANSACTION
napotkano, transakcja została już zatwierdzona.
Zobaczylibyśmy to samo, nawet gdyby transakcja napotkała błąd i została wycofana. Cofnięcie spowoduje zakończenie transakcji, a zatem nie będzie już więcej COMMIT
oświadczenia są wymagane.
Aby rozwiązać ten problem, po prostu usunęlibyśmy ostatnią COMMIT TRANSACTION
, a kod transakcji będzie wyglądał tak:
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
Transakcje niejawne
Jeśli masz włączone transakcje niejawne, możesz otrzymać inne wyniki niż w pierwszym przykładzie.
Jeśli ustawimy IMPLICIT_TRANSACTIONS
na ON
, oto co otrzymujemy:
SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Wynik:
+---------------------------------+----------------+ | 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)
Nie występuje błąd.
Dzieje się tak, ponieważ niektóre instrukcje T-SQL automatycznie uruchamiają transakcję po ich uruchomieniu. To tak, jakby były poprzedzone niewidzialną BEGIN TRANSACTION
oświadczenie.
Kiedy IMPLICIT_TRANSACTIONS
jest OFF
, oświadczenia te są zatwierdzane automatycznie. To tak, jakby zastąpiła je niewidzialna COMMIT TRANSACTION
oświadczenie. W tym scenariuszu transakcja jest w trybie automatycznego zatwierdzania.
Kiedy IMPLICIT_TRANSACTIONS
jest ON
, nie ma niewidocznej COMMIT TRANSACTION
oświadczenie. Te instrukcje są nadal uruchamiane przez niewidoczną BEGIN TRANSACTION
, ale muszą być wyraźnie zakończone.
Transakcja niejawna pozostaje w toku, dopóki nie zostanie jawnie zatwierdzona lub jawnie wycofana.
Dlatego w tym przykładzie nasz zabłąkany COMMIT TRANSACTION
oświadczenie było rzeczywiście potrzebne do zakończenia transakcji niejawnej.