我有一个“星星”数据库。一个是做一些工作;另外两个具有将元数据从第一个数据库拉入其引用表的作业。我想阻止任何人更新、删除或插入两个“奴隶”中引用表上的任何记录;这些表应该只由排定的作业更新。
我目前正在使用一个触发器来执行此操作,该触发器检查当前SID是否在USER_SCHEDULER_RUNNING_JOBS中,并具有我希望运行的作业名称。我想将此更改为使用我正在运行的作业的JOB_ID。
这是我目前的设置;假设一个非常简单的表格:
create table a ( b number );
以及以下工作:
begin
dbms_scheduler.create_job(
job_name => 'test_job'
, job_type => 'PLSQL_BLOCK'
, job_action => 'begin
merge into a a
using ( select 1 x from dual@db2 ) b
on (1 = 2)
when not matched then
insert values (b.x);
commit;
end;'
, start_date => sysdate
, repeat_interval => 'FREQ = MINUTELY;'
, enabled => true
);
end;
/
我用这个触发器:
create or replace trigger tr_blah
before insert or update on a
declare
l_ct number;
begin
select count(*) into l_ct
from user_scheduler_running_jobs
where session_id = sys_context('USERENV','SID')
and job_name = 'TEST_JOB'
;
if l_ct = 0 then
raise_application_error(-20000, 'FAIL');
end if;
end;
/
这是不雅的;但是,更糟糕的是,我必须为每个数据库中的每个表创建一个单独的触发器,并且每次都要更改作业名称。无法动态创建触发器;这会让人感到厌烦,而且有很大的错误空间。SYS_CONTEXT()
有参数FG_JOB_ID
和BG_JOB_ID
。它们的描述,特别是FG_JOB_ID
的描述 * 暗示 * 它们可能是当前运行作业的JOB_ID。将触发器更改为以下内容(我已经尝试了这两种方法):
create or replace trigger tr_a
before insert or update or delete on a
declare
l_ct number;
begin
raise_application_error(-20000, sys_context('USER_ENV', 'BG_JOB_ID'));
end;
/
导致以下
ORA-20000:
ORA-06512: at "REF.TR_A", line 4
ORA-04088: error during execution of trigger 'REF.TR_A'
ORA-06512: at line 2
这意味着FG_JOB_ID
和BG_JOB_ID
都是null。有没有一种方法可以确定当前会话中运行的作业的ID,这样我就不需要每次都使用JOB_NAME了?
1条答案
按热度按时间osh3o9ms1#
最优雅的解决方案是使用不同的数据库用户。确保作业在对表具有更新、插入和删除赠款的用户(可能是表的架构所有者)下运行。不要将这些赠款给予给其他用户。
不需要在触发器之类的东西上浪费时间。