Oracle PL/SQL: Aufruf einer Prozedur aus einem trigger
Ich bekomme diese Fehlermeldung immer wenn ich versuche auf das Feuer ein trigger nach dem einfügen auf Tabelle Passagiere. dieser Auslöser soll eine Prozedur aufrufen, die zwei Parameter nimmt der neu eingefügten Werte und basiert auf, dass es updates eine weitere Tabelle, die die Buchungs-Tabelle. ich bin jedoch immer diese Fehlermeldung:
ORA-04091: table AIRLINESYSTEM.PASSENGER is mutating, trigger/function may not see it
ORA-06512: at "AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE", line 11 ORA-06512: at
"AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE", line 15 ORA-06512: at
"AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE_T1", line 3 ORA-04088: error during execution of
trigger 'AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE_T1' (Row 3)
Ich befolgt und getestet, die Prozedur in der SQL-Befehlszeile und es funktioniert gut. Das problem scheint mit dem trigger. Dies ist der trigger-code:
create or replace trigger "CALCULATE_FLIGHT_PRICE_T1"
AFTER
insert on "PASSENGER"
for each row
begin
CALCULATE_FLIGHT_PRICE(:NEW.BOOKING_ID);
end;
Warum ist der trigger nicht, der die Prozedur aufruft?
- ORA-04091 sagt Ihnen, dass Sie ändern / Abfragen der Daten von Tabelle
PASSENGERS
im VerfahrenCALCULATE_FLIGHT_PRICE
- und das ist illegal. - Ich aktualisierte den Auslöser und bekomme immer noch den gleichen Fehler
- Ich habe das Verfahren
- Was @haki gesagt ist, dass Sie Abfragen, die gleichen, Sie haben einen Auslöser. So, nach dem einlegen einer Daten auf PASSAGIER-Tabelle der Auslöser ist die Abfrage der sable Tabelle auf
SELECT dob from passenger WHERE booking_id = p_bookingid;
- und dies ist nur illegal die Daten nicht begangen, aber, und Sie versuchen, das abrufen von Daten aus es. - Aber, ich habe mein trigger zum aufrufen der Prozedur nach einem insert auf Tabelle Passagiere
- Das ist, was das problem ist! Du bist das einfügen einer Zeile zu
passengers
Tabelle, auf die ein trigger ausgeführt wird, das eine gespeicherte Prozedur aufruft, die wiederumSELECT
s aus der "Passagiere" - Tabelle.SELECT
ing aus einer Tabelle, während es ausgeführt wird DMLs werden, ist verboten. Sie kann eineSELECT
aufpassengers
Tabelle von überall auf der trigger, als auch von den Prozeduren oder Funktionen aufgerufen wird, von der trigger. - Rufen Sie nicht die Verfahren
for each row
- entfernen dieser Klausel aus dem trigger Erklärung, und es sollte funktionieren.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ach du meine Güte... Sie versuchen eine
Dirty Read
im cursor. Dies ist ein schlechtes design.Wenn Sie zulassen, dass ein dirty read, es wieder die falsche Antwort, aber auch Sie gibt eine Antwort, die nie gegeben in der Tabelle. In einer multiuser-Datenbank, ein dirty read kann eine gefährliche Eigenschaft.
Der Punkt hier ist, dass dirty read ist nicht eine Funktion, sondern eine Haftung. In der Oracle-Datenbank, es ist einfach nicht nötig. Sie erhalten alle Vorteile des dirty read—kein verstopfen—ohne falsche Ergebnisse.
Lesen Sie mehr auf
"READ UNCOMMITTED isolation level"
die können dirty reads. Es bietet einen auf standards basierenden definition, die es erlaubt für nicht blockierende liest.Umgekehrt
Sind Sie missbrauchen die trigger. Ich meine, falschen trigger verwendet.
einfügen /aktualisieren einer Zeile in Tabelle A und einen trigger für die Tabelle Ein (für jede Zeile) führt eine Abfrage auf die Tabelle Ein (in einem Verfahren)??!!!
Oracle wirft ein ORA-04091, die einen erwarteten und normalen Verhalten, Oracle will um Sie zu schützen vor sich selbst, da es garantiert, dass jede Anweisung ist atomar (ich.e wird entweder fehlschlagen oder erfolgreich sind vollständig) und auch, dass jede Anweisung sieht eine konsistente Sicht auf die Daten
Würden Sie erwarten, dass die Abfrage (2) nicht zu sehen, die eingefügte Zeile auf (1). Dies wäre im Widerspruch
Lösung: -- verwenden Sie
before
stattafter
Sind Sie mit Datenbank-Trigger in einer Weise, die Sie nicht verwendet werden soll. Der Datenbank-trigger versucht, Lesen Sie die Tabelle es derzeit ändern. Wenn Oracle würde Ihnen erlauben, so zu tun, Sie wäre die Durchführung dirty reads.
Zum Glück, Oracle warnt Sie für Ihre Verhalten, und Sie können Sie ändern Ihr design.
Die beste Lösung wäre eine API erstellen. Ein Verfahren, vorzugsweise in einem Paket, das ermöglicht Ihnen das einfügen von Passagieren in genau der Weise, die Sie würde es mögen. In pseudo-PL/SQL-code:
Statt Ihre insert-Anweisung, Sie würde jetzt rufen Sie diese Prozedur. Und Ihre mutating table-problem wird verschwinden.
Wenn Sie darauf bestehen, mit einem Datenbank-trigger, dann würden Sie brauchen, um zu vermeiden, die select-Anweisung cursor c_passengers. Das macht keinen Sinn: Sie müssen nur eine Zeile eingefügt, in der Tabelle Passagiere und kennen alle Werte in der Spalte. Dann rufen Sie calculate_flight_price zum abrufen der Spalte Geburtsdatum, die Sie bereits kennen.
Fügen Sie einfach einen parameter P_DOB zu Ihrem calculate_flight_price Prozedur und rufen Sie es mit :new.dob, wie diese: