Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Jak naprawić „Żądanie COMMIT TRANSACTION nie ma odpowiadającej BEGIN TRANSACTION” w SQL Server

Jeśli otrzymujesz komunikat o błędzie 3902, poziom 16, który brzmi „Żądanie COMMIT TRANSACTION nie ma odpowiadającej BEGIN TRANSACTION”, to prawdopodobnie dlatego, że masz zabłąkany COMMIT oświadczenie.

Może to być spowodowane wdrożeniem obsługi błędów i zapominaniem, że już zatwierdziłeś lub wycofałeś transakcję w innym miejscu kodu.

Przykład błędu

Oto prosty przykład demonstrujący błąd:

SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;

Wynik:

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

Nastąpi to, jeśli Twój SET IMPLICIT_TRANSACTIONS jest OFF . Zobacz poniżej, co się stanie, gdy SET IMPLICIT_TRANSACTIONS jest ON .

Przykład błędu spowodowanego obsługą błędów

Może to być spowodowane wdrożeniem obsługi błędów i zapominaniem, że już zatwierdziłeś lub wycofałeś transakcję w innym miejscu kodu.

Na przykład:

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;

Wynik:

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

W tym przypadku miałem już COMMIT TRANSACTION w TRY blok. Więc do czasu drugiego COMMIT TRANSACTION napotkano, transakcja została już zatwierdzona.

Zobaczylibyśmy to samo, nawet gdyby transakcja napotkała błąd i została wycofana. Cofnięcie spowoduje zakończenie transakcji, a zatem nie będzie już więcej COMMIT oświadczenia są wymagane.

Aby rozwiązać ten problem, po prostu usunęlibyśmy ostatnią COMMIT TRANSACTION , a kod transakcji będzie wyglądał tak:

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

Transakcje niejawne

Jeśli masz włączone transakcje niejawne, możesz otrzymać inne wyniki niż w pierwszym przykładzie.

Jeśli ustawimy IMPLICIT_TRANSACTIONS na ON , oto co otrzymujemy:

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

Wynik:

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

Nie występuje błąd.

Dzieje się tak, ponieważ niektóre instrukcje T-SQL automatycznie uruchamiają transakcję po ich uruchomieniu. To tak, jakby były poprzedzone niewidzialną BEGIN TRANSACTION oświadczenie.

Kiedy IMPLICIT_TRANSACTIONS jest OFF , oświadczenia te są zatwierdzane automatycznie. To tak, jakby zastąpiła je niewidzialna COMMIT TRANSACTION oświadczenie. W tym scenariuszu transakcja jest w trybie automatycznego zatwierdzania.

Kiedy IMPLICIT_TRANSACTIONS jest ON , nie ma niewidocznej COMMIT TRANSACTION oświadczenie. Te instrukcje są nadal uruchamiane przez niewidoczną BEGIN TRANSACTION , ale muszą być wyraźnie zakończone.

Transakcja niejawna pozostaje w toku, dopóki nie zostanie jawnie zatwierdzona lub jawnie wycofana.

Dlatego w tym przykładzie nasz zabłąkany COMMIT TRANSACTION oświadczenie było rzeczywiście potrzebne do zakończenia transakcji niejawnej.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Złe nawyki:unikanie NULL w SQL Server

  2. Tally Table, aby wstawić brakujące daty między dwiema datami? SQL

  3. Jak używać ROW_NUMBER()?

  4. MySQL - znaczenie PRIMARY KEY, UNIQUE KEY i KEY używane razem podczas tworzenia tabeli

  5. DateDiff do wyjściowych godzin i minut