Błąd mutującego wyzwalacza Oracle występuje, gdy wyzwalacz odwołuje się do tabeli, do której należy wyzwalacz, co powoduje wyświetlenie komunikatu „ORA-04091:nazwa tabeli mutuje, wyzwalacz/funkcja może jej nie widzieć”.
Rzućmy okiem na istniejące obejścia.
Pierwsza, poprzez pakiet, jest stara i wydaje się skuteczna, jednak jej przygotowanie i uruchomienie zajmuje dużo czasu. Drugi jest prosty i wykonywany przy użyciu wyzwalaczy złożonych.
create table turtles as select 'Splinter' name, 'Rat' essence from dual union all select 'Leonardo', 'Painter' from dual union all select 'Rafael', 'Painter' from dual union all select 'Michelangelo', 'Painter' from dual union all select 'Donatello', 'Painter' from dual;
Kiedy Splinter zmutuje ze szczura w senseia, malarze będą musieli automatycznie zmienić się w ninja. Ten wyzwalacz wydaje się odpowiedni:
create or replace trigger tr_turtles_bue before update of essence on turtles for each row when ( new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei' ) begin update turtles set essence = 'Ninja' where essence = 'Painter'; end;
Jednak podczas aktualizowania rekordu:
update turtles set essence = 'Sensei' where name = 'Splinter'
Wystąpił następujący błąd:
ORA-04091:tabela SCOTT.TURTLES mutuje, wyzwalacz/funkcja może jej nie widzieć
Usuńmy ten wyzwalacz:
drop trigger tr_turtles_bue;
Metoda 1: Korzystanie z pakietu i wyzwalacza na poziomie instrukcji.
create or replace package pkg_around_mutation is bUpdPainters boolean; procedure update_painters; end pkg_around_mutation; / create or replace package body pkg_around_mutation is procedure update_painters is begin if bUpdPainters then bUpdPainters := false; update turtles set essence = 'Ninja' where essence = 'Painter'; end if; end; end pkg_around_mutation; / create or replace trigger tr_turtles_bue before update of essence on turtles for each row when ( new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei' ) begin pkg_around_mutation.bUpdPainters := true; end tr_turtles_bue; / create or replace trigger tr_turtles_bu after update on turtles begin pkg_around_mutation.update_painters; end tr_turtles_bu; /
Metoda 2: Korzystanie ze złożonych wyzwalaczy DML (dostępne od Oracle 11g).
create or replace trigger tr_turtles_ue for update of essence on turtles compound trigger bUpdPainters boolean; before each row is begin if :new.name = 'Splinter' and :old.essence = 'Rat' and :new.essence = 'Sensei' then bUpdPainters := true; end if; end before each row; after statement is begin if bUpdPainters then update Turtles set essence = 'Ninja' where essence = 'Painter'; end if; end after statement; end tr_turtles_ue;
Spróbujmy wykonać następujące czynności:
update turtles set essence = 'Sensei' where name = 'Splinter'
Nawet jeśli miałeś do czynienia z bardziej złożonym przypadkiem mutacji, możesz użyć powyższego pomysłu jako obejście. W wyzwalaczu na poziomie instrukcji, w przeciwieństwie do wyzwalacza na poziomie wiersza, nie występuje żadna mutacja. Możesz używać zmiennych (tagi, latchy, tabele PL SQL) w dodatkowym pakiecie lub zmiennych globalnych dla wszystkich sekcji wyzwalacza złożonego, co jest preferowane począwszy od wersji Oracle 11g. Więc teraz znasz również kung fu.
Dodatkowe informacje na temat wyzwalaczy można znaleźć pod adresem:Złożone wyzwalacze DML
Zapraszam do dodawania komentarzy.