在11g release 2(11.2)之前定时任务在包DBMS_JOB下,在其之后由DBMS_SCHEDULER替代,而DBMS_JOB仍然可以使用,但墙裂建议使用DBMS_SCHEDULER。
Oracle strongly recommends that you switch from
DBMS_JOBto Oracle Scheduler.
DBMS_JOB
查看任务:
select * from DBA_JOBS;
创建任务:
declare jobno number;BEGINDBMS_JOB.SUBMIT(job => jobno,what => 'STOCK_SNAPSHOT;',--行为,此处写的是存储过程,你也可以直接写SQL语句,不过要注意的是最后要记得加';'next_date => sysdate,--下次执行时间interval => 'TRUNC(last_day(sysdate)+1)' --任务执行间隔时间,此处为每个月1号的凌晨);end;
修改任务:
BEGINDBMS_JOB.WHAT(2,'select 1 from dual;');--DBMS_JOB包下job的属性修改就是使用与属性同名的函数,第一个参数为jobid,第二个为内容end;
删除任务:
beginDBMS_JOB.REMOVE(2);--2就是job的idend;
参考链接:Oracle docs
DBMS_SCHEDULER
查看任务:
select * from DBA_SCHEDULER_JOBS;
创建任务:
beginDBMS_SCHEDULER.CREATE_JOB(JOB_NAME => 'stock_snapshot_schedule',--job name,DBMS_JOB包没有的JOB_TYPE => 'STORED_PROCEDURE',--job type,DBMS_JOB包没有,用来指定行为类型,这里是存储过程,还有PLSQL_BLOCKjob_action => 'WLPLAT.STOCK_SNAPSHOT',--相当于DBMS_JOB的WHATSTART_DATE => SYSDATE,--任务开始时间--REPEAT_INTERVAL => 'TRUNC(last_day(sysdate)+1)',--任务执行间隔REPEAT_INTERVAL => 'freq=monthly;bymonthday=-1;byhour=23'COMMENTS => '每月1号凌晨将库存三张表转移至快照表');--commentsend;
两种REPEAT_INTERVAL的创建方式:
使用Calendar语法
使用PL/SQL
测试时间间隔:
DECLAREstartdate date;dateafter date;nextdate date;beginstartdate := SYSDATE;dateafter := startdate;for i in 1..24 loopdbms_scheduler.evaluate_calendar_string('FREQ=MONTHLY;BYMONTHDAY=-1;BYHOUR=23', startdate, dateafter, nextdate);dbms_output.put_line(to_char(nextdate,'YYYY-MM-DD HH24:MI'));dateafter := nextdate;end loop;end;
修改任务:
BEGINDBMS_SCHEDULER.SET_ATTRIBUTE (name => 'update_sales',--名字肯定是不可以改但必须提供的,除了名字外所有属性都可以更改attribute => 'repeat_interval',--属性value => 'freq=weekly; byday=wed');--值END;/
删除任务:
--删除多个JOB用逗号隔开,并且可以提供jobclass并删除此class下的所有job--jobclass即为job的类别,在创建时可以指定BEGINDBMS_SCHEDULER.DROP_JOB ('job1, job3, sys.jobclass1, sys.jobclass2');END;/
执行任务:
--RUN_JOB可以不按计划的执行一次任务beginDBMS_SCHEDULER.RUN_JOB(JOB_NAME => 'STOCK_SNAPSHOT_SCHEDULE',USE_CURRENT_SESSION => FALSE);end;
启动任务:
--与DBMS_JOB不同的是DBMS_SCHEDULER创建的任务默认是关闭的,我们需要手动开启,否则并不会按计划执行--禁用即为DISABLEBEGINDBMS_SCHEDULER.ENABLE('STOCK_SNAPSHOT_SCHEDULE');end;
复制任务:
--copy原任务的所有属性beginDBMS_SCHEDULER.COPY_JOB('job3','job2');end;
查看任务日志:
SELECT * FROM (SELECT t.*FROM SYS.DBA_SCHEDULER_JOB_RUN_DETAILS tORDER BY LOG_DATE DESC) WHERE ROWNUM <= 501SELECT * FROM (SELECT t.*FROM SYS.DBA_SCHEDULER_JOB_LOG tORDER BY LOG_DATE DESC) WHERE ROWNUM <= 501
定时任务使用时碰到的问题:
在项目中设置过任务之后就不管了,以为万无一失,结果到时间却没自动执行,排查了很久终于发现原来是时区的问题
select current_timestamp from dual;--本地时区--输出2019-12-31 08:15:01.453053 +00:00,Greenwitch Mean Time
select systimestamp from dual;--数据库系统时区--输出2019-12-31 16:13:59.775550 +08:00,东八区
时区不一致,在这个例子中系统时间是东八区而创建任务的是格林时间所以任务会延迟(也就是延迟8小时),于是我们在创建任务的时候要改一点(你也可以将自己本地session的时区更改为正确的)
beginDBMS_SCHEDULER.CREATE_JOB(JOB_NAME => 'stock_snapshot_schedule',JOB_TYPE => 'STORED_PROCEDURE',job_action => 'WLPLAT.STOCK_SNAPSHOT',START_DATE => systimestamp, --SYSDATE改为systimestamp--如果是自定义时间,可以用to_timestamp_tz函数将字符串转换成带时区的时间--select to_timestamp_tz('2010-01-03 11:09:00 +8:00','YYYY-MM-DD HH24:MI:SS TZH:TZM') from dual;REPEAT_INTERVAL => 'freq=monthly;bymonthday=-1;byhour=23'COMMENTS => '每月1号凌晨将库存三张表转移至快照表');--commentsend;
参考链接:Oracle docs
参考链接:why are my jobs not running
