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

Chyba spouštění:Aktuální transakci nelze potvrdit a nemůže podporovat operace, které zapisují do souboru protokolu

K této chybě dochází při použití bloku try/catch uvnitř transakce. Podívejme se na triviální příklad:

SET XACT_ABORT ON

IF object_id('tempdb..#t') IS NOT NULL
    DROP TABLE #t
CREATE TABLE #t (i INT NOT NULL PRIMARY KEY)

BEGIN TRAN
    INSERT INTO #t (i) VALUES (1)
    INSERT INTO #t (i) VALUES (2)
    INSERT INTO #t (i) VALUES (3)
    INSERT INTO #t (i) VALUES (1) -- dup key error, XACT_ABORT kills the batch
    INSERT INTO #t (i) VALUES (4) 

COMMIT  TRAN
SELECT * FROM #t

Když čtvrté vložení způsobí chybu, dávka se ukončí a transakce se vrátí zpět. Zatím žádné překvapení.

Nyní se pokusme tuto chybu vyřešit pomocí bloku TRY/CATCH:

SET XACT_ABORT ON
IF object_id('tempdb..#t') IS NOT NULL
    DROP TABLE #t
CREATE TABLE #t (i INT NOT NULL PRIMARY KEY)

BEGIN TRAN
    INSERT INTO #t (i) VALUES (1)
    INSERT INTO #t (i) VALUES (2)
    BEGIN TRY
        INSERT INTO #t (i) VALUES (3)
        INSERT INTO #t (i) VALUES (1) -- dup key error
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE()
    END CATCH  
    INSERT INTO #t (i) VALUES (4)
    /* Error the Current Transaction cannot be committed and 
    cannot support operations that write to the log file. Roll back the transaction. */

COMMIT TRAN
SELECT * FROM #t

Zachytili jsme chybu duplicitního klíče, ale jinak na tom nejsme lépe. Naše dávka se stále ukončuje a naše transakce se stále vrací zpět. Důvod je ve skutečnosti velmi jednoduchý:

Blokování TRY/CATCH neovlivňuje transakce.

Vzhledem k tomu, že je XACT_ABORT ON, v okamžiku, kdy dojde k chybě duplicitního klíče, je transakce odsouzena k zániku. Je hotovo pro. Bylo smrtelně zraněno. Bylo to střeleno do srdce...a chyba je na vině. TRY/CATCH dává SQL Server...špatné jméno. (promiň, nemohl jsem odolat)

Jinými slovy, NIKDY zavázat a bude VŽDY být vrácen zpět. Jediné, co blok TRY/CATCH dokáže, je zlomit pád mrtvoly. Můžeme použít XACT_STATE() funkce, abyste zjistili, zda je naše transakce potvrditelná. Pokud tomu tak není, jedinou možností je odvolat transakci.

SET XACT_ABORT ON -- Try with it OFF as well.
IF object_id('tempdb..#t') IS NOT NULL
    DROP TABLE #t
CREATE TABLE #t (i INT NOT NULL PRIMARY KEY)

BEGIN TRAN
    INSERT INTO #t (i) VALUES (1)
    INSERT INTO #t (i) VALUES (2)

    SAVE TRANSACTION Save1
    BEGIN TRY
        INSERT INTO #t (i) VALUES (3)
        INSERT INTO #t (i) VALUES (1) -- dup key error
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE()
        IF XACT_STATE() = -1 -- Transaction is doomed, Rollback everything.
            ROLLBACK TRAN
        IF XACT_STATE() = 1 --Transaction is commitable, we can rollback to a save point
            ROLLBACK TRAN Save1
    END CATCH  
    INSERT INTO #t (i) VALUES (4)

IF @@TRANCOUNT > 0
    COMMIT TRAN
SELECT * FROM #t

Spouštěče se vždy provádějí v kontextu transakce, takže pokud se v nich můžete vyhnout použití TRY/CATCH, věci jsou mnohem jednodušší.

Pro řešení vašeho problému by se CLR Stored Proc mohl připojit zpět k serveru SQL Server v samostatném připojení a spustit dynamické SQL. Získáte možnost spustit kód v nové transakci a logika zpracování chyb se snadno píše a je snadno pochopitelná v C#.




  1. SQL tabulka s položkou seznamu vs SQL tabulka s řádkem pro každou položku

  2. Výkon zobrazení Oracle s rownum

  3. Kdy jsou počítané sloupce vhodné?

  4. Použijte v('APP_USER') jako výchozí hodnotu pro sloupec v Oracle Apex