【问题标题】:I have a trigger autonomous but only execute one time in the same session我有一个自动触发器,但在同一个会话中只执行一次
【发布时间】:2013-11-27 17:00:23
【问题描述】:

我有一个独立的触发器,但在同一个会话中只执行一次,然后什么都不做

CREATE OR REPLACE TRIGGER tdw_insert_unsus
BEFORE INSERT ON unsuscription_fact FOR EACH ROW
DECLARE
 PRAGMA AUTONOMOUS_TRANSACTION;
 v_id_suscription               SUSCRIPTION_FACT.ID_SUSCRIPTION%TYPE;
 v_id_date_suscription          SUSCRIPTION_FACT.ID_DATE_SUSCRIPTION%TYPE;
 v_id_date_unsuscription        SUSCRIPTION_FACT.ID_DATE_UNSUSCRIPTION%TYPE;
 v_suscription                  DATE;
 v_unsuscription                DATE; 
 v_live_time                    SUSCRIPTION_FACT.LIVE_TIME%TYPE;
BEGIN
    SELECT id_suscription, id_date_suscription 
    INTO v_id_suscription, v_id_date_suscription
    FROM(
        SELECT id_suscription, id_date_suscription
        FROM suscription_fact
        WHERE id_mno = :NEW.ID_MNO
        AND id_provider = :NEW.ID_PROVIDER
        AND ftp_service_id = :NEW.FTP_SERVICE_ID
        AND msisdn = :NEW.MSISDN
        AND id_date_unsuscription IS NULL
        ORDER BY id_date_suscription DESC
    )
    WHERE ROWNUM = 1;

    -- calculate time
    v_unsuscription := to_date(:NEW.id_date_unsuscription,'yyyymmdd');
    v_suscription := to_date(v_id_date_suscription,'yyyymmdd');
    v_live_time := (v_unsuscription - v_suscription);

    UPDATE suscription_fact SET id_date_unsuscription = :NEW.id_date_unsuscription, 
    id_time_unsuscription = :NEW.id_time_unsuscription, live_time = v_live_time
    WHERE id_suscription = v_id_suscription;

    COMMIT;

    EXCEPTION
        WHEN NO_DATA_FOUND THEN
        ROLLBACK;
END;
/

如果我在第一次或第二次插入值时效果很好但在不工作之后,但如果我注销会话并且登录适用于第一次或第二次插入 什么问题?,我用的是oracle 10g

【问题讨论】:

  • 也许您遇到了 no_data_found 异常?取出异常处理程序,看看是否抛出错误。
  • 将自动触发器用于除日志记录之外的任何事情几乎总是一个错误(至少是不好的代码味道)

标签: sql database oracle triggers oracle10g


【解决方案1】:

您正在使用自治事务来解决触发器无法查询其表本身的事实。您遇到了臭名昭著的 mutating table 错误,并且您发现将触发器声明为自治事务会使错误消失。

不过你运气不好,这根本不能解决问题:

  • 首先,任何事务逻辑都会丢失。您无法回滚 suscription_fact 表上的更改,它们已提交,而您的主事务没有并且可以回滚。因此,您也失去了数据完整性。
  • 触发器看不到新行,因为新行尚未提交!由于触发器在独立事务中运行,它无法看到主事务所做的未提交更改:您将遇到完全错误的结果。

这就是为什么您永远不应该在自主事务中执行任何业务逻辑。 (有合法的应用程序,但它们几乎完全限于日志记录/调试)。

在您的情况下,您应该:

  1. 更新您的逻辑,使其不需要查询您的表(仅当新行比存储在id_date_unsuscription 中的旧值更新时更新suscription_fact)。
  2. 忘记在触发器中使用业务逻辑并使用正确更新所有表的过程或使用视图,因为这里我们有一个明显的冗余数据案例。
  3. 使用workaround that actually works (by Tom Kyte)

我强烈建议在这里使用 (2)。不要使用触发器来编写业务逻辑。它们很难编写没有错误,也更难维护。使用过程可确保所有相关代码都集中在一个位置(包或过程),易于阅读和遵循,并且不会产生不可预见的后果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2012-02-14
    • 2017-05-07
    • 1970-01-01
    • 2010-09-26
    相关资源
    最近更新 更多