Se ricevi il messaggio di errore 3902, livello 16, che dice "La richiesta COMMIT TRANSACTION non ha una corrispondente BEGIN TRANSACTION", probabilmente è perché hai un COMMIT
randagio dichiarazione.
Potresti ottenerlo a causa dell'implementazione della gestione degli errori e della dimenticanza di aver già eseguito il commit o il rollback della transazione in un'altra parte del codice.
Esempio di errore
Ecco un semplice esempio per dimostrare l'errore:
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Risultato:
(7 rows affected) Msg 3902, Level 16, State 1, Line 2 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Ciò si verificherà se il tuo SET IMPLICIT_TRANSACTIONS
è OFF
. Vedi sotto per cosa succede quando SET IMPLICIT_TRANSACTIONS
è ON
.
Esempio di errore dovuto alla gestione degli errori
Potresti ottenerlo a causa dell'implementazione della gestione degli errori e della dimenticanza di aver già eseguito il commit o il rollback della transazione in un'altra parte del codice.
Ad esempio:
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;
Risultato:
(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.
In questo caso, avevo già COMMIT TRANSACTION
nel TRY
bloccare. Quindi per il momento il secondo COMMIT TRANSACTION
è stato rilevato, la transazione era già stata salvata.
Vedremmo lo stesso anche se la transazione avesse riscontrato un errore e fosse stato annullato. Un rollback interromperà la transazione e, pertanto, nessun ulteriore COMMIT
le dichiarazioni sono obbligatorie.
Quindi, per risolvere questo problema, rimuoveremmo semplicemente l'ultima COMMIT TRANSACTION
e il codice della transazione sarebbe simile a questo:
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
Transazioni implicite
Se hai abilitato le transazioni implicite, potresti ottenere risultati diversi rispetto al primo esempio.
Se impostiamo IMPLICIT_TRANSACTIONS
su ON
, ecco cosa otteniamo:
SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Risultato:
+---------------------------------+----------------+ | 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)
Non si verifica alcun errore.
Questo perché alcune istruzioni T-SQL avviano automaticamente una transazione quando vengono eseguite. È come se fossero preceduti da un invisibile BEGIN TRANSACTION
dichiarazione.
Quando IMPLICIT_TRANSACTIONS
è OFF
, queste affermazioni vengono automaticamente salvate. È come se gli succedesse un invisibile COMMIT TRANSACTION
dichiarazione. In questo scenario, la transazione è in modalità autocommit.
Quando IMPLICIT_TRANSACTIONS
è ON
, non esiste un COMMIT TRANSACTION
invisibile dichiarazione. Queste istruzioni sono ancora avviate da un invisibile BEGIN TRANSACTION
, ma devono essere interrotti in modo esplicito.
Una transazione implicita rimane in corso fino a quando non viene eseguito il commit o il rollback esplicito.
Pertanto, in questo esempio, il nostro randagio COMMIT TRANSACTION
era effettivamente necessaria per terminare la transazione implicita.