2013-03-08 65 views
1

我我的包,我入队多个作业是这样的:如何等待所有调度程序作业完成?

dbms_scheduler.create_job 
    (job_name  => p_job_name 
    , job_type  => 'PLSQL_BLOCK' 
    , job_action => p_sql_code 
    , start_date => SYSDATE 
    , enabled  => TRUE 
    , comments  => 'Running batch jobs in parallel'); 

一旦我这样做了,我想开始尽可能多的并行作业,我需要阻塞,直到所有的工作都有完成。

目前我不得不睡觉和轮询表ALL_SCHEDULER_JOB_RUN_DETAILSALL_SCHEDULER_JOBS并检查作业的状态。这似乎是一个非常难看的解决方案。这里是我使用的SQL:

PROCEDURE run_jobs 
    (p_jobs StringTableType 
    , p_sql  VARCHAR2(4000)) 
IS 

    l_jobs   StringTableType; 
    l_status  sys_type.STRING; 
    l_additional_info sys_type.text; 
    l_done   BOOLEAN; 
    i    PLS_INTEGER; 

BEGIN 

    l_jobs := p_jobs; 

    -- Submit jobs 
    FOR i IN 1..l_jobs.COUNT LOOP 

    dbms_scheduler.create_job 
    (job_name  => l_jobs(i) 
    , job_type  => 'PLSQL_BLOCK' 
    , job_action => p_sql 
    , start_date => SYSDATE 
    , enabled  => TRUE 
    , comments  => 'Running batch jobs in parallel'); 

    END LOOP; 

    -- now wait untile all jobs are finished 
    l_done := FALSE; 

    WHILE NOT l_done LOOP 

    DBMS_LOCK.sleep(5); 

    l_done := TRUE; 

    i := l_jobs.FIRST; 
    WHILE i IS NOT NULL LOOP 

     WITH jobs_log 
      AS (SELECT job_name, state status, '' additional_info 
       FROM all_scheduler_jobs 
       UNION 
       SELECT job_name, status, additional_info 
       FROM all_scheduler_job_run_details 
       ) 
     SELECT status, additional_info 
     INTO l_status, l_additional_info 
     FROM jobs_log 
     WHERE job_name = p_jobs (i); 

     --Analyze job status 
     CASE 
     WHEN l_status = 'RUNNING' THEN 
      l_done := FALSE; 

     WHEN l_status = 'SUCCEEDED' THEN 
      l_jobs.DELETE(i); 

     WHEN l_status = 'FAILED' THEN 
      l_jobs.DELETE(i); 

     ELSE 
      l_done := FALSE; 

     END CASE; 

     i := l_jobs.NEXT(i); 

    END LOOP; 

    END LOOP; 

END run_jobs; 

如何才能阻止我的代码,直到所有的工作完成?任何人都可以给我一个例子,如果有更好的方法来做到这一点?

+2

>我怎么能等到我所有的调度工作已经完成? 打个盹; ^) – 2013-03-08 14:35:45

+4

看到这个[回答相似的问题](http://stackoverflow.com/a/4600487/119634),亚当霍克斯建议通过dbms_scheduler创建一个链。它看起来像一个优雅的解决方案 – 2013-03-08 14:52:59

+0

@VincentMalgrat,一个很好的资源。谢谢。它解决了这个问题。 – 2013-11-27 15:06:02

回答

1

不幸的是,Oracle中的会话间通信并不像OS中的进程间通信那么方便。但是你可以

lock table ... in exclusive mode 

工作中,并用

select ... for update 
1

执行作业终止等待,如果你没有很多的工作,你可以使用DBMS_LOCK包来创建自己的锁定对象。用一些知名的名字为每个作业创建一个。让作业获得锁,并且主作业等待所有锁被释放。

1
DECLARE 
    cnt NUMBER:=1; 
BEGIN 
    WHILE cnt>=1 
    LOOP 
    SELECT count(1) INTO cnt FROM dba_scheduler_running_jobs srj 
    WHERE srj.job_name IN ('TEST_JOB1','TEST_JOB2'); 
    IF cnt>0 THEN 
     dbms_lock.sleep (5); 
    END IF; 
    END LOOP; 
    dbms_output.put_line('ASASA'); 
END; 
+0

欢迎来到SO。你能解释一下,为什么这能解决OP问题? – m00am 2016-02-25 10:05:56