none
Trigger commit / rollback

    Dotaz

  • Ahoj,

    mám problém, že když v triggeru přidávám hodnotu do jiné tabulky a tento insert vrátí chybu, tak mi to rollbackne i tu původní tabulku. Já potřebuji aby to prošlo.

    CREATE TRIGGER TrigTest
    ON DBTEST.TableTest
    AFTER INSERT, UPDATE
    AS 
    BEGIN
     Inset into DBTEST.TableTest2
     Select * From inserted
    END GO

    Když ale změním DBTEST.TableTest2 na DBTEST.TableTest2XX (neexistující tabulku), tak logicky vrátí chybu. Tím se ale rollbackne i insert do tabulky DBTEST.TableTest. Tohle ale nechci, potřebuji aby insert proběhl.

    Zkoušel jsem i vnořenou transkaci, try catch. Prostě všechno.

    Nějaké nápady?

    26. ledna 2011 12:21

Odpovědi

  • Takže jsme se posunuli od neexistující tabulky k jiné databázi a teď už je to jiný server...

    Trigger, který je v podstatě lokální záležitost používaná převážně pro validace dat a audit, by se neměl používat pro práci s jinými servery (dle mého názoru).

    Taky vlastně nechápu, proč potřebuješ trigger, který "nemusí" pracovat, nebo který pracuje jen když je zapnutý nějaký server? Když ho úplně zrušíš, poběží to zcela bez problémů...

    Ale abych byl konstruktivnější: Vzhledem k tomu, že data na vzdáleném serveru nemusí být zapsána, udělej trigger, který bude zapisovat na lokálním serveru a na data z takové tabulky můžeš už přistupovat odkudkoli přes linked server nebo je replikovat i jinak. Nebudeš omezen nutností zapnutí vzdáleného serveru, vše bude spolehlivější, rychlejší atd.

     

    27. ledna 2011 17:01

Všechny reakce

  • Trigger se obvykle vytváří proto, aby jeho kód proběhl, a to bez chyb. Trigger je v podstatě integrální součástí příkazu, který ho spustil, a pokud nastane chyba v triggeru, tak je logické, že se nedokončí ani příkaz, který ho spustil.

    Odkaz na chybějící tabulku je tak závažná chyba, že ji nelze řešit ani odchycením pomocí TRY CATCH bloku v triggeru samotném, ale až ve volajícím programu. A vrátí-li trigger takovou chybu, nemůže už být transakce dokončena a musí být zrušena...

    Řešení je tedy test na existenci tabulky DBTEST.TableTest2 v triggeru a korektní návrat:

    if (SELECT object_id('DBTEST.TableTest2')) IS NOT NULL
     Inset into DBTEST.TableTest2
      Select * From inserted
    
    

    Rovněž doporučuji přidat TRY CATCH blok ke kódu (INSERT nebo UPDATE), který způsobí volání triggeru a test hodnoty XACT_STATE(), která ukáže, zda je transakci možno ukončit pomocí COMMIT nebo je nutný ROLLBACK.

     

    26. ledna 2011 23:05
  • Rozumím tomu.

    Jenže rollback v SQL serveru mi vrátí chybu na aplikační vrstvě, což si nemůžu dovolit. Aplikační vrstva se očetřit nedá jelikož se jedná o napojení Lotus přes DECS na SQL server.

    Tabulka samozřejmě bude existovat vždy ale jelikož se jedná o jinou DB a ta může mít výpadek, tak musím zajistit chod aplikace nezávisle na jiné DB.

    Odzkouším tvoje řešení.

    Díky

    27. ledna 2011 10:37
  • Takže jiná databáze...

    To asi bude nejlepší udělat ještě test pomocí  databasepropertyex() a případně i has_dbaccess()

    27. ledna 2011 12:17
  • Jinou DB jsem myslel např. na jiném stroji. Konkrétně ORACLE přes linkovaný server.

    Zkoušel jsem sp_linkdeserver. Což vrátí chybu a jdu do CATCH. Ale tahle chyba je propagována do Lotus a ten to vyhodnotí jako chybu. Tzn. potřeboval bych buď přkaz, který hodnotu nevrací jako chybu, nebo zakázat posílání chybovách zpráv.

     

    26.01.2011 18:05:40    Monitor failure --

    ErrorRecord:  HResult: 0x80040e14

    Description: The transaction ended in the trigger. The batch has been aborted.

    SQLErrorInfo: 42000

     

    Zkoušel jsem nastvit chybu pomocí RAISERROR a ta se propaguje do LOTUS.

     

    ErrorRecord:  HResult: 0x80040e14

    Description: Nefunguje LinkovanýServer

    SQLErrorInfo: 01000

     

    Lotus jako aplikační vrstva mi ale řekne, že se jedná o chybu a nedovolí záznam uložit.

    Už opravdu nevím.

    27. ledna 2011 12:43
  • Takže jsme se posunuli od neexistující tabulky k jiné databázi a teď už je to jiný server...

    Trigger, který je v podstatě lokální záležitost používaná převážně pro validace dat a audit, by se neměl používat pro práci s jinými servery (dle mého názoru).

    Taky vlastně nechápu, proč potřebuješ trigger, který "nemusí" pracovat, nebo který pracuje jen když je zapnutý nějaký server? Když ho úplně zrušíš, poběží to zcela bez problémů...

    Ale abych byl konstruktivnější: Vzhledem k tomu, že data na vzdáleném serveru nemusí být zapsána, udělej trigger, který bude zapisovat na lokálním serveru a na data z takové tabulky můžeš už přistupovat odkudkoli přes linked server nebo je replikovat i jinak. Nebudeš omezen nutností zapnutí vzdáleného serveru, vše bude spolehlivější, rychlejší atd.

     

    27. ledna 2011 17:01