sql >> Databáze >  >> RDS >> Sqlserver

Jak opravit „Požadavek COMMIT TRANSACTION nemá odpovídající BEGIN TRANSACTION“ v SQL Server

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.


  1. Změna z SQLite na PostgreSQL v novém projektu Rails

  2. Zkontrolujte, zda v Oracle existuje tabulka

  3. Laravel 5.2 – Použít řetězec jako vlastní primární klíč pro výmluvnou tabulku se stane 0

  4. mysql_fetch_assoc():zadaný argument není platným zdrojem výsledků MySQL v php