Pokud se vám zobrazuje chybová zpráva 3902, úroveň 16, která zní „Požadavek COMMIT TRANSACTION nemá žádnou odpovídající ZAČÁTEK TRANSAKCI“, je to pravděpodobně proto, že máte zatoulaný COMMIT
prohlášení.
Mohli byste to získat kvůli implementaci zpracování chyb a zapomenutí, že jste již transakci provedli nebo vrátili zpět na jiném místě vašeho kódu.
Příklad chyby
Zde je jednoduchý příklad demonstrující chybu:
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Výsledek:
(7 rows affected) Msg 3902, Level 16, State 1, Line 2 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
K tomu dojde, pokud SET IMPLICIT_TRANSACTIONS
je OFF
. Níže se dozvíte, co se stane, když SET IMPLICIT_TRANSACTIONS
je ON
.
Příklad chyby způsobené zpracováním chyb
Mohli byste to získat kvůli implementaci zpracování chyb a zapomenutí, že jste již transakci provedli nebo vrátili zpět na jiném místě vašeho kódu.
Například:
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;
Výsledek:
(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.
V tomto případě jsem již měl COMMIT TRANSACTION
v TRY
blok. Takže do druhého COMMIT TRANSACTION
došlo, transakce již byla potvrzena.
Totéž bychom viděli, i kdyby v transakci došlo k chybě a byla vrácena zpět. Vrácení transakce ukončí transakci, a proto již žádné COMMIT
jsou vyžadována prohlášení.
Abychom tento problém vyřešili, jednoduše odstraníme poslední COMMIT TRANSACTION
a kód transakce by vypadal takto:
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
Implicitní transakce
Pokud máte povoleny implicitní transakce, můžete získat jiné výsledky než v prvním příkladu.
Pokud nastavíme IMPLICIT_TRANSACTIONS
na ON
, dostaneme toto:
SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Výsledek:
+---------------------------------+----------------+ | 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)
Nedochází k žádné chybě.
Důvodem je, že některé příkazy T-SQL automaticky zahájí transakci, když jsou spuštěny. Je to, jako by jim předcházelo neviditelné BEGIN TRANSACTION
prohlášení.
Když IMPLICIT_TRANSACTIONS
je OFF
, tyto příkazy jsou automaticky potvrzeny. Je to, jako by po nich následoval neviditelný COMMIT TRANSACTION
prohlášení. V tomto scénáři je transakce v režimu automatického potvrzení.
Když IMPLICIT_TRANSACTIONS
je ON
, neexistuje žádný neviditelný COMMIT TRANSACTION
prohlášení. Tyto příkazy jsou stále spuštěny neviditelným BEGIN TRANSACTION
, ale je třeba je explicitně ukončit.
Implicitní transakce zůstává v průběhu, dokud není buď explicitně potvrzena, nebo explicitně odvolána.
Proto v tomto příkladu naše zbloudilá COMMIT TRANSACTION
bylo skutečně potřeba k ukončení implicitní transakce.