Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment réparer "La demande COMMIT TRANSACTION n'a pas de BEGIN TRANSACTION correspondante" dans SQL Server

Si vous recevez l'erreur Msg 3902, niveau 16, qui indique "La requête COMMIT TRANSACTION n'a pas de BEGIN TRANSACTION correspondante", c'est probablement parce que vous avez un COMMIT errant. déclaration.

Vous pourriez obtenir cela en raison de la mise en œuvre de la gestion des erreurs et de l'oubli que vous avez déjà validé ou annulé la transaction ailleurs dans votre code.

Exemple d'erreur

Voici un exemple simple pour illustrer l'erreur :

SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;

Résultat :

(7 rows affected)
Msg 3902, Level 16, State 1, Line 2
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.

Cela se produira si votre SET IMPLICIT_TRANSACTIONS est OFF . Voir ci-dessous ce qui se passe lorsque SET IMPLICIT_TRANSACTIONS est ON .

Exemple d'erreur due à la gestion des erreurs

Vous pourriez obtenir cela en raison de la mise en œuvre de la gestion des erreurs et de l'oubli que vous avez déjà validé ou annulé la transaction ailleurs dans votre code.

Par exemple :

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;

Résultat :

(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.

Dans ce cas, j'avais déjà COMMIT TRANSACTION dans le TRY bloc. Ainsi, au moment où le deuxième COMMIT TRANSACTION a été rencontré, la transaction avait déjà été validée.

Nous verrions la même chose même si la transaction avait rencontré une erreur et avait été annulée. Une annulation mettra fin à la transaction et, par conséquent, aucun autre COMMIT déclarations sont obligatoires.

Donc, pour résoudre ce problème, nous supprimerions simplement le dernier COMMIT TRANSACTION , et le code de transaction ressemblerait à ceci :

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

Transactions implicites

Si vous avez activé les transactions implicites, vous pourriez obtenir des résultats différents du premier exemple.

Si nous définissons IMPLICIT_TRANSACTIONS sur ON , voici ce que nous obtenons :

SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;

Résultat :

+---------------------------------+----------------+
| 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)

Aucune erreur ne se produit.

En effet, certaines instructions T-SQL démarrent automatiquement une transaction lors de leur exécution. C'est comme s'ils étaient précédés d'un BEGIN TRANSACTION invisible déclaration.

Lorsque IMPLICIT_TRANSACTIONS est OFF , ces instructions sont automatiquement validées. C'est comme s'ils étaient remplacés par un COMMIT TRANSACTION invisible déclaration. Dans ce scénario, la transaction est en mode autocommit.

Lorsque IMPLICIT_TRANSACTIONS est ON , il n'y a pas de COMMIT TRANSACTION invisible déclaration. Ces instructions sont toujours lancées par un BEGIN TRANSACTION invisible , mais ils doivent être terminés explicitement.

Une transaction implicite reste en cours jusqu'à ce qu'elle soit explicitement validée ou explicitement annulée.

Par conséquent, dans cet exemple, notre erreur COMMIT TRANSACTION était en fait nécessaire pour mettre fin à la transaction implicite.