如何确保一项作业永远不会运行多个实例?
例如,如果我有一个计划每分钟运行一次的作业,但它实际上运行了三分钟,我不希望该作业的第二个和第三个实例同时启动和运行。
使用dbms_job
,您永远不会同时运行两个作业实例。如果我interval
在未来 1 分钟内做这样的事情,而程序需要 3 分钟才能运行
declare
l_jobno pls_integer;
begin
dbms_job.submit( l_jobno,
'begin proc_that_takes_3_minutes(); end;',
sysdate,
'sysdate + interval ''1'' minute' );
end;
/
Run Code Online (Sandbox Code Playgroud)
的interval
表达只在现有运行完成后进行评价。不会同时运行 3 个作业实例。该作业将每 4 分钟运行一次。
这就是为什么您经常听到人们说作业随时间“漂移”的原因——作业计划在凌晨 4 点以“sysdate + 1”的间隔运行,因此它每天运行的时间稍晚一些。如果作业运行时间为 1 分钟,则在 2 个月后,它现在会在凌晨 5 点之后运行。这就是为什么interval
如果您想每天凌晨 4 点运行,您通常希望您的代码类似于“trunc(sysdate+1) + interval '4' hours”。
如果您想提供额外的保护以防万一有人试图在作业运行的同时在不同的会话中运行该过程,您可以dbms_lock.request
在尝试获取用户定义的锁之前调用该过程做实际工作。
create or replace procedure what_the_job_does
as
l_status integer;
begin
l_status := dbms_lock.request( 'MY_LOCK_NAME' );
if( l_status in (1,4) )
then
<<do actual work>>
end if;
end;
Run Code Online (Sandbox Code Playgroud)