|
||||||
Trigger und das Mutating Table Error ProblemEines vorweg. Ein “Mutating Table Error” (Error ORA-04091 bei einer Oracle Datenbank) ist immer ein Hinweis auf schlecht geschriebenen Code. Jeder der an einem Trigger für seine Oracle Datenbank arbeitet, sollte sich vorher gründlich überlegen, ob er nicht genau diese Fehlermeldung durch unüberlegten Code generiert. Soweit zum ermahnen …. und jetzt …. ich habe den Fehler natürlich prompt ebenfalls produziert. Das kommt davon, wenn man sich nicht vorher überlegt was man da tut. Punkt 1, warum passiert mir das?
Punkt 2, was kann ich jetzt dagegen machen?
Anbei ein kleines Beispiel zur Demonstration des Problems und wie es behoben werden kann. Bitte keine Kommentare bezüglich Tabellenaufbau und Triggerprogrammierung. Es handelt sich schlicht um ein Beispiel, bei dem bewusst auf zusätzlichen Code verzichtet wurde, damit der Leser sich auf die Lösung des eigentlichen Problems konzentrieren kann. Es ist kein Muster, das so in der Praxis eingesetzt wird oder werden sollte. Zuerst erstellen wir eine einfache Tabelle mit ID-Spalte und fügen einen Datensatz ein: CREATE TABLE “KOSTEN”
( “ID” NUMBER(5,0) NOT NULL ENABLE, “TYP” VARCHAR2(20) NOT NULL ENABLE, “MENGE” NUMBER NOT NULL ENABLE, “ART” VARCHAR2(200), CONSTRAINT “KOSTEN_PK” PRIMARY KEY (”ID”) ENABLE ) / CREATE OR REPLACE TRIGGER “BI_KOSTEN” before insert on “KOSTEN” for each row begin select “KOSTEN_SEQ”.nextval into :NEW.ID from dual; end; / ALTER TRIGGER “BI_KOSTEN” ENABLE / INSERT INTO “KOSTEN” Danach erstellen wir einen Trigger, der die Menge beim Datensatz mit TYP = ‘PLAN’ reduzieren soll, sobald ein Datensatz mit TYP = ‘REAL’ eingefügt wird. CREATE OR REPLACE TRIGGER “TR_DECREASE_PLAN”
after insert on “KOSTEN” for each row declare v_menge number; v_neue_menge number; begin select “MENGE” into v_menge from “KOSTEN” where “TYP” = ‘PLAN’; v_neue_menge := v_menge - :NEW.”MENGE”; UPDATE “KOSTEN” set “MENGE” = v_neue_menge where “TYP” = ‘PLAN’; end; Wird jetzt ein REAL Datensatz eingefügt, so kommt es zu der Fehlermeldung Mutating Table: INSERT INTO “KOSTEN”
(”TYP”, “MENGE”, “ART”) VALUES (’REAL’, ‘20′, ‘Haushalt’) / ORA-04091: Tabelle SYSTEM.KOSTEN wird gerade geändert, Trigger/Funktion sieht dies möglicherweise nicht Um das zu umgehen, erstellen wir erst eine temporäre Tabelle: CREATE GLOBAL TEMPORARY TABLE “KOSTEN_TEMP”
( “ID” NUMBER(5,0) NOT NULL ENABLE, “MENGE” NUMBER NOT NULL ENABLE, “ART” VARCHAR2(200) ) ON COMMIT DELETE ROWS; / Jetzt wird ein Trigger programmiert, der beim Einfügen von Datensätzen mit dem TYP = ‘REAL’ diese in die temporäre Tabelle kopiert: CREATE OR REPLACE TRIGGER “TR_COPY_REAL”
after insert on “KOSTEN” for each row begin INSERT INTO “KOSTEN_TEMP” (”ID”, “MENGE”, “ART”) VALUES (:NEW.”ID”, :NEW.”MENGE”, :NEW.”ART”); end; / Der Trigger “TR_DECREASE_PLAN” wird zu einem Statement Trigger umgeschrieben (indem FOR EACH ROW entfernt wird). Er feuert somit einmal nach jeder INSERT Transaktion, holt sich den passenden Datensatz aus der temporären Tabelle und berechnet die neue Planmenge. (Beispiel funktioniert so natürlich nicht, wenn mit einem Insert mehrere Datensätze eingefügt werden). CREATE OR REPLACE TRIGGER “TR_DECREASE_PLAN”
after insert on “KOSTEN” declare v_menge_real number; v_menge_plan number; v_neue_menge number; begin select “MENGE” into v_menge_real from “KOSTEN_TEMP”; select “MENGE” into v_menge_plan from “KOSTEN” where “TYP” = ‘PLAN’; v_neue_menge := v_menge_plan - v_menge_real; UPDATE “KOSTEN” set “MENGE” = v_neue_menge where “TYP” = ‘PLAN’; Wird nun ein neuer Datensatz mit TYP = ‘REAL’ eingefügt, tritt der Mutating Table Fehler nicht mehr auf. Die Referenzen zu den jeweiligen Artikeln in den Fussnoten sollten das Ganze noch näher erklären. 1 comment to Trigger und das Mutating Table Error Problem |
||||||
|
Copyright © 2010 Joachim Uhls Blog - All Rights Reserved
|
||||||
Hallo Joachim,
müsste der zweite Trigger nicht gefeuert werden nach einem Insert auf KOSTEN_TEMP. Falls ja, dann bliebe die Fehlermeldung ‘wird gerade geändert, Trigger/Funktion sieht dies möglicherweise nicht’ doch bestehen, oder? Hab ich einen Denkfehler?
Viele Grüße
Aness