我有一个触发器自动但只在同一个会话中执行一次

时间:2013-11-27 17:00:23

标签: sql database oracle triggers oracle10g

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

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

1 个答案:

答案 0 :(得分:4)

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

虽然没有运气,但这根本无法解决问题:

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

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

在你的情况下,你应该:

  1. 更新您的逻辑,以便不需要查询您的表格(仅当新行比suscription_fact中存储的旧值更新时才更新id_date_unsuscription
  2. 忘记在触发器中使用业务逻辑并使用正确更新所有表或使用视图的过程,因为这里我们有一个明确的冗余数据案例。
  3. 使用workaround that actually works (by Tom Kyte)
  4. 我强烈建议在这里使用(2)。不要使用触发器来编写业务逻辑。他们很难写,没有错误,更难以维护。使用程序可以保证所有相关代码都分组在一个地方(包或程序),易于阅读和遵循,并且没有不可预见的后果。