您正在调用 DBMS_SCHEDULER.STOP_JOB () 并将 force 设置为 false。根据文档,这意味着它将尝试“使用中断机制优雅地停止作业”。没有关于这种“中断机制”的详细信息,互联网上的网站只是简单地重复文档,没有任何进一步的见解。
让我们看看会发生什么。这是一个模仿你的程序。当它运行到完成时,T42 中将有 32 条记录。
create or replace procedure p_job_tst is
n simple_integer := 1;
begin
delete from t42;
insert into t42 (stage, id) values (1, n);
commit;
for i in 1..30 loop
n := n+1;
insert into t42 (stage, id) values (2, n);
commit;
dbms_lock.sleep(2);
end loop;
n := n+1;
insert into t42 (stage, id) values (3, n);
commit;
end;
/
对dbms_lock.sleep() 的调用意味着它会执行一分钟,这使我们可以在运行中终止工作,而不必非常快地打字。这是工作:
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'apc.my_job1',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN p_job_tst; END;',
start_date => systimestamp + interval '10' second,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=3',
enabled => TRUE,
comments => 'StackOverflow Test');
END;
/
已经开始工作,让我们等到它运行,然后停止它:
SQL> select job_name, state, run_count from dba_scheduler_jobs where job_name = 'MY_JOB1';
JOB_NAME STATE RUN_COUNT
------------------------------ --------------- ----------
MY_JOB1 SCHEDULED 2
SQL> select job_name, state, run_count from dba_scheduler_jobs where job_name = 'MY_JOB1';
JOB_NAME STATE RUN_COUNT
------------------------------ --------------- ----------
MY_JOB1 RUNNING 2
SQL> exec sys.dbms_scheduler.STOP_JOB(job_name=>'apc.my_job1', force=>false);
PL/SQL procedure successfully completed.
SQL> select job_name, state, run_count from dba_scheduler_jobs where job_name = 'MY_JOB1';
JOB_NAME STATE RUN_COUNT
------------------------------ --------------- ----------
MY_JOB1 SCHEDULED 3
SQL>
在我停止工作之前,T42 有十条记录。 T42目前的内容?
SQL> r
1* select * from t42 order by stage, id
ID STAGE
---------- ----------
1 1
2 2
3 2
4 2
5 2
6 2
7 2
8 2
9 2
10 2
11 2
ID STAGE
---------- ----------
12 2
12 rows selected.
SQL>
所以作业被优雅地停止了,但不是在程序结束时。似乎中断机制正在寻找一个没有锁或长时间运行的进程的简洁断点。就像你的代码一样,我的代码有很多这样的断点。每个commit 结束一个事务并释放所有锁。
从调度程序的角度来看,这很好,因为“优雅地”停止工作似乎很容易。当然,从应用程序的角度来看,这完全是一场噩梦。该作业将在未知状态中结束。部分工作将已经完成并已提交,而有些部分将丢失。没有简单的方法可以判断每种有多少,同时您的数据库将处于潜在的不一致状态。
有与发出commit 语句相关的最佳实践:commit 一次,在工作单元结束时。后台作业是一个工作单元,因此它应该恰好有一个 commit 语句,就在终止 end 之前(假设您的块没有异常处理程序部分,它应该有)。