2013-11-27 26 views
0

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

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

+0

也许你正在碰到no_data_found异常?取出异常处理程序,看看是否会抛出错误。 – OldProgrammer

+0

它几乎总是一个错误(至少不好的代码味道)使用自动触发器除了日志以外的任何事情 –

回答

4

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

没有运气,你虽然,这根本不会解决问题:

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

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

在你的情况,你应该:

  1. 更新你的逻辑,这样它并不需要查询您的表(更新suscription_fact仅如果新行比存储在id_date_unsuscription旧值更近)。
  2. 忘掉在触发器中使用业务逻辑,并使用正确更新所有表或使用视图的过程,因为在这里我们有明确的冗余数据情况。
  3. 使用workaround that actually works (by Tom Kyte)

我强烈建议在这里使用(2)。不要使用触发器来编写业务逻辑。他们很难写出没有错误,更难以维持。使用程序保证所有相关的代码被分组在一个地方(一个程序包或一个程序),易于阅读和遵循,并且没有无法预料的后果。