Oracle -根据触发器是否由作业触发而更改触发器的行为

kiz8lqtg  于 2023-10-16  发布在  Oracle
关注(0)|答案(3)|浏览(131)

我需要我的触发器(它在更新表时发送消息)以某种方式运行,如果它是由作业触发的。此作业每小时运行一次,并发送大量消息。有什么办法可以让我做吗。
我试着按照下面的方法来确定invoker是否是一个作业,但似乎不起作用:

select count(1) into nIsJob from V$SESSION x where x.sid in (select t.session_id from all_scheduler_running_jobs t) and x.sid=sys_context('USERENV', 'SID');

整个触发器是这样的:

create or replace trigger tg_spot_in_other_hour
  before update
  on BREAKS 
  for each row
declare
 vBody     VARCHAR2(4000);
 nIsJob NUMBER;
begin
  
  select count(1) into nIsJob from V$SESSION x where x.sid in (select t.session_id from all_scheduler_running_jobs t) and x.sid=sys_context('USERENV', 'SID');
 
if (:new.id_break_types NOT IN (2) or (:new.id_break_types = 5 and nIsJob=0)) and TRUNC(:new.BREAK_TIME / gv.fis / 60 / 60)<>TRUNC(:old.BREAK_TIME / gv.fis / 60 / 60) and (:new.break_date >= sysdate or :old.break_date >= sysdate) then

select 'Break on '||ch.label||' ' into vBody
from channels ch
where ch.id_channels=:new.id_channels;

vBody:=vBody||:new.break_date||' moved from '||pcg_system.num2dur(:old.break_time,'HH:MM')||' to '||pcg_system.num2dur(:new.break_time,'HH:MM');

for x_b in (select  c.id_backoffice,c.contract_number,c.label
from spots s, contracts c
where c.id_contracts=s.id_contracts
and s.id_breaks=:new.id_breaks) loop

INSERT INTO messages
      (id_users,
       header,
       message,
       created)
values (x_b.id_backoffice,'Spot moved to different hour',vBody||' Contract: '||x_b.contract_number||' ('||x_b.label||')',sysdate)  ;

end loop;

end if;

end tg_spot_in_other_hour;
h5qlskok

h5qlskok1#

您可以通过DBMS_APPLICATION_INFO使用上下文来更改触发器的行为。
您可以将触发器更改为具有WHEN子句,该子句查找上下文值,例如:client_info

create or replace trigger tg_spot_in_other_hour
  before update
  on BREAKS 
  for each row
  when (sys_context('userenv', 'client_info') is null
    or sys_context('userenv', 'client_info') != 'FROM_JOB')

declare
...

从文档中:

WHEN(条件)

指定数据库为触发语句影响的每一行计算的SQL条件。如果受影响行的condition值为TRUE,则为该行运行 trigger_body;否则,trigger_body 不会为该行运行。无论condition的值如何,触发语句都会运行。
然后在作业运行的过程中,在开始时设置上下文:

dbms_application_info.set_client_info('FROM_JOB');

你也可以/应该在结束时再次清除它,以防会话保持活动状态并被重用(所以也可能在异常处理程序中):

dbms_application_info.set_client_info(null);

所以现在当触发事件是由你的作业引起的时候,WHEN子句将计算为false,触发器主体将不会被执行;否则,它将评估为true,并且它仍将发送消息。
没有什么可以阻止其他人手动设置上下文,但是如果你认为这是可能的,你可以确保使用的值是不寻常的或者不太可能是随机选择的;和/或使用上下文值(信息、模块、动作...)的组合。
使用SCHEDULER_JOBFG_JOB_IDBG_JOB_ID作为@PaulW建议是gong更简单,因为你不需要改变作业的过程来设置自己的东西。我将把它留在这里,因为这在其他情况下可能很有用,比如区分来自应用程序的调用,或者单个与批处理(但不是调度程序!))作业,或在升级期间...

jfgube3f

jfgube3f2#

有许多方法可以做到这一点。以下是其他几个:
1.查看当前会话的pname,看看它是否是一个作业进程:

SELECT COUNT(*)
  INTO var_exists
  FROM v$session s,
       v$process p
 WHERE s.sid = SYS_CONTEXT('USERENV','SID')
   AND s.paddr = p.addr
   AND p.pname LIKE 'J%'

IF var_exists > 0
THEN
   -- is a job
END IF;

1.或者更简单地,使用SYS_CONTEXT值,如SCHEDULER_JOBFG_JOB_IDBG_JOB_ID

IF SYS_CONTEXT('USERENV','SCHEDULER_JOB') = 'Y'
THEN
  -- is a job
END IF;

IF SYS_CONTEXT('USERENV','BG_JOB_ID') IS NOT NULL
   THEN
     -- is a job
   END IF;

您还可以将dba_scheduler_jobs.job_namev$session.action字段匹配。有很多选择。

nmpmafwu

nmpmafwu3#

您可以使用

owa_util.who_called_me(owner, name, lineno, caller);

它将返回所有的细节,你可以区分,如果它是由工作或不解雇。
详细信息请参见文档。

相关问题