Oracle no_data_found 异常未传播到调度程序中

Oracle no_data_found exception is not propagated into the scheduler

令我们沮丧的是,我们发现 no_data_found 异常没有传播到 Oracle 调度程序中。

如果您有一个执行 select x into my_var 的过程并且 select 因 no_data_found 而失败,该过程将失败,但调度程序 运行 将执行此过程仍然成功,连锁店和工作也会成功。

我想知道是否 no_data_found 是唯一受到这种影响的例外,或者是否还有其他例外?

此外,到目前为止,我们提出的唯一解决方案是在过程本身中捕获 no_data_found 并引发用户定义的异常。它确实有效,但这意味着如果我们想要防止代码失败,我们将不得不进入每个过程并引入这个异常处理块。

你能想到一个不涉及代码更改的解决方案吗?也许是数据库级别的设置?

请看下面的代码

----------------过程

create procedure test as
 l_var number;
 begin
   select 0 
     into l_var 
     from dual 
    where 1 = 0; 
 end;
 /

----------------程序

BEGIN
  dbms_scheduler.create_program (
    program_name   => 'PRG_TEST',
    program_type   => 'STORED_PROCEDURE',
    program_action => 'TEST',
    enabled        => TRUE,
  );
END;
/

----------------工作

BEGIN
 dbms_scheduler.create_job (
   job_name             => 'JOB_TEST',
   program_name         => 'PRG_TEST',
   enabled              =>  TRUE,
  );
END;
/

我们正在将过程包装到一个程序中,而这个程序又被包装到一个作业中。因为我们启用了作业,所以它会 运行 立即成功。

但是,如果我们像这样执行程序:

begin
   test;
end;

它将(正确地)失败 - no_data_found 异常。问题是:有没有一种方法可以使作业失败而不必更改过程的代码?

这似乎是 DBMS_SCHEDULER 的一个已知问题:参见示例:

要解决此问题,您可以将作业类型更改为 PLSQL_BLOCK。以下是我创建作业时发生的情况,检查其状态,在后台给它一秒钟左右的时间 运行 并再次检查:

SQL> create or replace procedure test as
  2  begin
  3    raise no_data_found;
  4  end;
  5  /

Procedure created.

SQL> BEGIN
  2   dbms_scheduler.create_job (
  3     job_name             => 'JOB_TEST',
  4     job_type             => 'PLSQL_BLOCK',
  5     job_action           => 'TEST',
  6     enabled              =>  TRUE,
  7     auto_drop            =>  FALSE
  8    );
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> SELECT job_name, state, failure_count FROM user_scheduler_jobs WHERE job_name = 'JOB_TEST';

JOB_NAME                       STATE           FAILURE_COUNT
------------------------------ --------------- -------------
JOB_TEST                       SCHEDULED                   0

SQL> EXEC dbms_lock.sleep(1);

PL/SQL procedure successfully completed.

SQL> SELECT job_name, state, failure_count FROM user_scheduler_jobs WHERE job_name = 'JOB_TEST';

JOB_NAME                       STATE           FAILURE_COUNT
------------------------------ --------------- -------------
JOB_TEST                       FAILED                      1