Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como corrigir “A solicitação COMMIT TRANSACTION não tem BEGIN TRANSACTION correspondente” no SQL Server


Se você está recebendo o erro Msg 3902, Level 16, que diz "A solicitação COMMIT TRANSACTION não tem BEGIN TRANSACTION correspondente", provavelmente é porque você tem um COMMIT perdido demonstração.

Você pode estar recebendo isso devido à implementação do tratamento de erros e esquecendo que já confirmou ou reverteu a transação em outro lugar do seu código.

Exemplo de erro


Aqui está um exemplo simples para demonstrar o erro:
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.

Isso ocorrerá se o seu SET IMPLICIT_TRANSACTIONS está OFF . Veja abaixo o que acontece quando SET IMPLICIT_TRANSACTIONS está ON .

Exemplo de erro devido ao tratamento de erros


Você pode estar recebendo isso devido à implementação do tratamento de erros e esquecendo que já confirmou ou reverteu a transação em outro lugar do seu código.

Por exemplo:
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.

Nesse caso, eu já tinha COMMIT TRANSACTION no TRY quadra. Então, quando o segundo COMMIT TRANSACTION foi encontrado, a transação já havia sido confirmada.

Veríamos o mesmo mesmo que a transação encontrasse um erro e fosse revertida. Uma reversão encerrará a transação e, portanto, não haverá mais COMMIT declarações são necessárias.

Então, para corrigir esse problema, simplesmente removemos o último COMMIT TRANSACTION , e o código da transação ficaria assim:
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

Transações Implícitas


Se você tiver transações implícitas habilitadas, poderá obter resultados diferentes do primeiro exemplo.

Se definirmos IMPLICIT_TRANSACTIONS para ON , eis o que obtemos:
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)

Nenhum erro ocorre.

Isso ocorre porque certas instruções T-SQL iniciam automaticamente uma transação quando são executadas. É como se eles fossem precedidos por um BEGIN TRANSACTION invisível demonstração.

Quando IMPLICIT_TRANSACTIONS está OFF , essas instruções são confirmadas automaticamente. É como se eles fossem sucedidos por um invisível COMMIT TRANSACTION demonstração. Nesse cenário, a transação está no modo de confirmação automática.

Quando IMPLICIT_TRANSACTIONS está ON , não há COMMIT TRANSACTION invisível demonstração. Essas instruções ainda são iniciadas por um BEGIN TRANSACTION invisível , mas eles precisam ser encerrados explicitamente.

Uma transação implícita permanece em andamento até que seja explicitamente confirmada ou explicitamente revertida.

Portanto, neste exemplo, nosso COMMIT TRANSACTION perdido foi realmente necessária para encerrar a transação implícita.