sql >> Base de Datos >  >> RDS >> Sqlserver

Cómo arreglar "La solicitud COMMIT TRANSACTION no tiene BEGIN TRANSACTION correspondiente" en SQL Server

Si recibe el mensaje de error 3902, nivel 16, que dice "La solicitud COMMIT TRANSACTION no tiene BEGIN TRANSACTION correspondiente", probablemente se deba a que tiene un COMMIT perdido. declaración.

Podría estar obteniendo esto debido a la implementación del manejo de errores y al olvido de que ya comprometió o revirtió la transacción en otra parte de su código.

Ejemplo de error

Aquí hay un ejemplo simple para demostrar el error:

SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;

Resultado:

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

Esto ocurrirá si su SET IMPLICIT_TRANSACTIONS está OFF . Vea a continuación lo que sucede cuando SET IMPLICIT_TRANSACTIONS está ON .

Ejemplo de error debido a la gestión de errores

Podría estar obteniendo esto debido a la implementación del manejo de errores y al olvido de que ya comprometió o revirtió la transacción en otra parte de su código.

Por ejemplo:

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;

Resultado:

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

En este caso, ya tenía COMMIT TRANSACTION en el TRY cuadra. Entonces, para cuando el segundo COMMIT TRANSACTION se encontró, la transacción ya se había confirmado.

Veríamos lo mismo incluso si la transacción hubiera encontrado un error y se revirtiera. Una reversión finalizará la transacción y, por lo tanto, no más COMMIT se requieren declaraciones.

Entonces, para solucionar este problema, simplemente eliminaríamos la última COMMIT TRANSACTION , y el código de transacción se vería así:

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

Transacciones implícitas

Si tiene habilitadas las transacciones implícitas, es posible que obtenga resultados diferentes a los del primer ejemplo.

Si configuramos IMPLICIT_TRANSACTIONS a ON , esto es lo que obtenemos:

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

Resultado:

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

No se produce ningún error.

Esto se debe a que ciertas declaraciones de T-SQL inician automáticamente una transacción cuando se ejecutan. Es como si estuvieran precedidos por un BEGIN TRANSACTION invisible declaración.

Cuando IMPLICIT_TRANSACTIONS está OFF , estas sentencias se confirman automáticamente. Es como si les sucediera una COMMIT TRANSACTION invisible. declaración. En este escenario, la transacción está en modo de confirmación automática.

Cuando IMPLICIT_TRANSACTIONS está ON , no hay COMMIT TRANSACTION invisible declaración. Estas declaraciones aún se inician con un BEGIN TRANSACTION invisible , pero deben finalizarse explícitamente.

Una transacción implícita permanece en curso hasta que se confirma explícitamente o se revierte explícitamente.

Por lo tanto, en este ejemplo, nuestro COMMIT TRANSACTION perdido la declaración era realmente necesaria para finalizar la transacción implícita.