27

我有一个在导入转储后必须运行的 sql 脚本。除了脚本所做的其他事情外,它还执行以下操作:

BEGIN 
--remove program          
SYS.DBMS_SCHEDULER.DROP_PROGRAM(program_name=>'STATISTICS_COLUMNS_PROG',FORCE=>TRUE);
--remove job
SYS.DBMS_SCHEDULER.DROP_JOB (job_name => 'STATISTICS_COLUMNS_JOB');
END; 

有时作业已经在原始模式中被删除,转储没有作业并且脚本失败:

ERROR at line 1:
ORA-27475: "DMP_6633.STATISTICS_SET_COLUMNS_JOB" must be a job 
ORA-06512: at "SYS.DBMS_ISCHED", line 213 
ORA-06512: at "SYS.DBMS_SCHEDULER", line 657 
ORA-06512: at line 5 

如果作业不存在但仍然可以删除它,我该如何避免这种失败?

4

1 回答 1

59

您可以将两种主要模式应用于异常处理;“三思而后行”(LBYL)和“请求宽恕比请求许可更容易”(EAFP)。LBYL 主张在尝试放弃之前检查该作业是否存在。EAFP 将涉及尝试删除作业,然后捕获并忽略该特定错误(如果发生)。

如果您要申请 LBYL,您可以查询系统视图USER_SCHEDULER_JOBS以查看您的工作是否存在。如果是,请放下它。

declare
   l_job_exists number;
begin
   select count(*) into l_job_exists
     from user_scheduler_jobs
    where job_name = 'STATISTICS_COLUMNS_JOB'
          ;

   if l_job_exists = 1 then
      dbms_scheduler.drop_job(job_name => 'STATISTICS_COLUMNS_JOB');
   end if;
end;

对于 EAFP,它略有不同;通过命名内部定义的异常并使用您要捕获的错误代码实例化它来定义您自己的异常。如果随后引发该错误,则什么也不做。

declare
   job_doesnt_exist EXCEPTION;
   PRAGMA EXCEPTION_INIT( job_doesnt_exist, -27475 );
begin
   dbms_scheduler.drop_job(job_name => 'STATISTICS_COLUMNS_JOB');
exception when job_doesnt_exist then
   null;
end;

关于第二种方法,有两点值得注意。

  1. 捕获此特定异常引发的错误。使用它可以实现相同的目标,EXCEPTION WHEN OTHERS但我强烈建议要这样做。

    如果你处理一个异常,你应该确切地知道你将如何处理它。您不太可能有能力正确处理每一个 Oracle 异常OTHERS,如果您这样做,您可能应该将它们记录在它们会被注意到的地方。引用 Oracle 的避免和处理异常指南

    尽可能为命名异常编写异常处理程序,而不是使用 OTHERS 异常处理程序。

  2. Oracle 的异常传播工作从内部块到外部块,因此错误的最初原因将是第一个异常。

于 2013-11-24T19:35:44.187 回答