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.