본문 바로가기
Data & Programming/Oracle

[오라클-오류] ORA-04091: table is mutating, trigger/function may not see it (테이블이 변경되어, 트리거/함수가 볼 수 없습니다)

by 눈부셔™ 2023. 8. 26.
728x90

[Oracle-오류] ORA-04091: table is mutating, trigger/function may not see it (테이블이 변경되어, 트리거/함수가 볼 수 없습니다)

ORA-04091은 오라클 데이터베이스에서 트리거가 트리거를 소유한 테이블을 참조할 때 발생하는 오류로, "ORA-04091: table name is mutating, trigger/function may not see it"라는 메시지가 나타납니다.

ORA-04091


오류 내용

ORA-04091 오류는 트리거가 소유한 테이블을 참조하려고 할 때 발생합니다. 

이 경우 트리거 내에서 소유한 테이블을 참조하면 트리거가 실행되면서 테이블 내용이 변경되는데, 이 변경된 테이블 내용을 다시 트리거가 참조하게 되어 무한 루프가 발생할 수 있습니다. 

 

 

해결 방법

  • 트리거를 사용하지 않는 것이 가장 좋은 방법입니다. 대부분의 PL/SQL 개발자들은 반드시 필요한 경우가 아니면 트리거를 사용하지 않습니다.
  • "after" 또는 "instead of" 트리거를 사용하는 것이 좋습니다. 이렇게 하면 mutating table과 관련된 문제를 피할 수 있습니다. 예를 들어, ":after update on xxx"와 같은 트리거를 사용하면 원래의 업데이트가 완료되고 테이블이 mutating 상태가 아니게 됩니다.
  • 트리거 구문을 다시 작성하여 row-level과 statement-level 트리거의 조합으로 mutating table을 회피할 수 있습니다.
  • autonomous transaction으로 트리거를 표시하여 프로시저를 호출하는 테이블로부터 독립적으로 만들 수 있습니다.

 

예시

  • 자체참조하는 트리거 예시
1
2
3
4
5
6
7
8
9
-- 자체참조를 발생시키는 트리거
CREATE OR REPLACE TRIGGER self_referencing_trigger
AFTER INSERT ON my_table
FOR EACH ROW
BEGIN
    INSERT INTO my_table (column1) VALUES ('new value');
END;
/
-- 오류 메시지: ORA-04091: 테이블 또는 뷰에 존재하지 않는 객체
cs
    • AFTER INSERT 트리거 예시
1
2
3
4
5
6
7
8
9
10
-- "employees" 테이블에 새 직원 추가 후, 직원 수를 업데이트하는 "AFTER INSERT" 트리거
CREATE OR REPLACE TRIGGER update_employee_count
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
    UPDATE department
    SET employee_count = employee_count + 1
    WHERE department_id = :new.department_id;
END;
/
cs
    • AFTER UPDATE 트리거 예시
1
2
3
4
5
6
7
8
9
-- "orders" 테이블에서 주문 상태가 변경된 후, 주문 이력을 로깅하는 "AFTER UPDATE" 트리거
CREATE OR REPLACE TRIGGER log_order_status_change
AFTER UPDATE ON orders
FOR EACH ROW
BEGIN
    INSERT INTO order_status_log (order_id, old_status, new_status, change_date)
    VALUES (:old.order_id, :old.status, :new.status, SYSDATE);
END;
/
cs
    • INSTEAD OF INSERT 트리거 예시
1
2
3
4
5
6
7
8
-- "customers_view" 뷰에 대한 "INSTEAD OF INSERT" 트리거로 데이터 삽입 방지 및 처리
CREATE OR REPLACE TRIGGER prevent_insert_on_view
INSTEAD OF INSERT ON customers_view
BEGIN
    RAISE_APPLICATION_ERROR(-20001'뷰에는 직접 데이터를 삽입할 수 없습니다.');
END;
/

cs
  • INSTEAD OF UPDATE 트리거 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- "orders_view" 뷰에 대한 "INSTEAD OF UPDATE" 트리거로 복잡한 업데이트 동작 수행
CREATE OR REPLACE TRIGGER perform_complex_update
INSTEAD OF UPDATE ON orders_view
FOR EACH ROW
BEGIN
    UPDATE orders
    SET order_status = :new.status,
        last_updated = SYSDATE
    WHERE order_id = :old.order_id;
    
    INSERT INTO order_status_history (order_id, old_status, new_status, change_date)
    VALUES (:old.order_id, :old.status, :new.status, SYSDATE);
END;
/
cs

 

 

결론적으로, 

ORA-04091 오류는 트리거가 트리거를 소유한 테이블을 참조할 때 발생합니다. 

이 오류를 방지하고 해결하기 위해서는 트리거 로직을 재설계하거나 자체참조를 방지하는 방법을 고려해야 합니다. 

또한 트리거 사용을 지양하거나, "after" 또는 "instead of" 트리거를 사용하거나, 트리거 구문을 다시 작성하거나, autonomous transaction으로 트리거를 설정하는 등의 방법이 있습니다.

 

#ORACLE  #오라클  #오라클 오류코드  #ORA-04091  #오류해결  #객체 부재  #PL/SQL  #DB오류  #트리거  #mutating 

728x90