【问题标题】:Trigger update in Oracle, mutating error在 Oracle 中触发更新,变异错误
【发布时间】:2015-06-17 09:31:00
【问题描述】:

我有一个名为“收藏夹”的简单表格。

Favorites
| username | type_of_movie | like_or_dislike |

数据如下:

AAA, Action, Like
AAA, Romance, Dislike
...

我已经创建了一个触发器来计算最喜欢的类型并阻止用户喜欢所有类型。

CREATE OR REPLACE TRIGGER trgLike
BEFORE INSERT OR UPDATE ON Favorite
FOR EACH ROW
DECLARE
    count number;
BEGIN
 SELECT
 COUNT(username) INTO count
 FROM
 Favorite
 WHERE
 username= :NEW.username AND like_or_dislike = 'Like';
 IF (count = 3) THEN
    RAISE_APPLICATION_ERROR(-20000,'Too much liking');
 END IF;    
END;
/

我希望用户能够喜欢 3 种类型的电影。

插入触发器工作得很好,但是当我尝试更新不喜欢的东西时,我得到了错误 ORA-04091 table is in mutation。第 6 行出错。

如何防止这种情况发生?我已经搜索过了,似乎我的更新会改变我选择的值,但我不知道如何。

我使用的是 Oracle 版本 11g。

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    出现错误消息,因为您的触发器同时查询Favorite 表,而表内容正在更改(UPDATEINSERT)。

    为了解决这个问题,您需要三个触发器和一个小包:

    CREATE OR REPLACE PACKAGE state_pkg AS
        type ridArray IS TABLE OF rowid INDEX BY binary_integer;
        newRows ridArray;
        empty ridArray;
    END;
    /
    
    CREATE OR REPLACE TRIGGER trgLike_clear_table 
        BEFORE INSERT OR UPDATE ON Favorite 
    BEGIN 
        state_pkg.newRows := state_pkg.empty;
    END;
    /
    
    CREATE OR REPLACE TRIGGER trgLike_capture_affected_rows 
        AFTER INSERT OR UPDATE ON Favorite FOR EACH ROW 
    BEGIN 
        state_pkg.newRows(state_pkg.newRows.count +1) := :new.rowid;
    END;
    /
    
    CREATE OR REPLACE TRIGGER trgLike_do_work 
        AFTER INSERT OR UPDATE ON Favorite 
    DECLARE    
        likes NUMBER;
    BEGIN 
      FOR i IN 1..state_pkg.newRows.count LOOP
        SELECT COUNT(*) INTO likes
          FROM Favorite
        WHERE username = (SELECT username FROM Favorite WHERE rowid = state_pkg.newRows(i))
          AND like_or_dislike = 'Like';
          IF (likes = 3) THEN
              RAISE_APPLICATION_ERROR(-20000, 'Too much liking');
          END IF;
        END LOOP;
    END;
    / 
    

    AskTom 上有一个nice article 与此相关。

    p.s.:请参阅上面的更新和测试版本。

    【讨论】:

    • 谢谢!我现在明白了。与此同时,我认识的人建议我使用 pragma Autonomous_transaction;
    • 自治事务确实提供了一种有趣且强大的方法,我经常在日志记录或审计的上下文中使用它们。但是,我不确定它们是否适合您的情况。例如,检查这篇文章中的答案:stackoverflow.com/questions/23774882/…。最后,这取决于特定的任务;但总的来说,我同意贾斯汀的观点。
    • 为此再加一百万++ 我们已经在这些讨厌的变异触发器问题上浪费了好几个小时,因为我们的数据库是多年来创建的,并且不是经过设计的,礼貌的说法是别的。这行得通。
    【解决方案2】:

    您可以在触发器中使用物化视图。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      • 2018-02-19
      • 2021-09-20
      • 2022-11-12
      • 1970-01-01
      • 2017-06-10
      • 1970-01-01
      相关资源
      最近更新 更多