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.