dbms_scheduler包的功能比dbms_job包强大很多,但是很多初学者直接被它的复杂性吓跑了,跟着我,只需几分钟就会用了。
大多数人看到这个包里的函数和函数里众多的参数,就开始晕菜了,不要被这些表象迷惑了,其实这些东西都是围绕着三个基本概念,schedule,program和job。oracle是为了复用的目的,提炼出了调度的这三个要素,弄懂这三个要素,立刻豁然开朗。
schedule表示调度计划表。调度从什么时间开始被调度,什么时候结束,以什么频度调度。使用DBMS_SCHEDULER.CREATE_SCHEDULE过程创建schedule。
begin
DBMS_SCHEDULER.CREATE_SCHEDULE (
schedule_name => ¨daily_schedule¨,
start_date => SYSDATE,
repeat_interval => ¨FREQ=DAILY ; INTERVAL=1¨,
comments => ¨every one day¨);
END;
/
其中repeat_interval参数,支持两种格式:
- dbms_job里的interval格式,建议让这种晦涩语法见鬼去吧
- 日历表达式(linux系统的crontab使用的格式)
日历表达式分为三部分: 第一部分是频率,也就是”FREQ”这个关键字,它是必须指定的; 第二部分是时间间隔,也就是”INTERVAL”这个关键字,取值范围是1-999. 它是可选的参数; 第三部分是附加的参数,可用于精确地指定日期和时间,它也是可选的参数,下面这些值都是合法的:
BYMONTH,BYWEEKNO,BYYEARDAY,BYMONTHDAY,BYDAY
BYHOUR,BYMINUTE,BYSECOND
看几个例子就会用了
每隔2小时运行一次
repeat_interval => 'FREQ=HOURLY; INTERVAL=2'
每天运行一次
repeat_interval => 'FREQ=DAILY'
每周的1,3,5运行
repeat_interval => 'FREQ=WEEKLY; BYDAY=MON,WED,FRI"
每年的3,6,9,12月的18号运行
repeat_interval => 'FREQ=YEARLY; BYMONTH=MAR,JUN,SEP,DEC; BYMONTHDAY=18'
另外使用dbms_scheduler.evaluate_calendar_string可以方便的计算出什么时候执行该调度。
program表示调度应该做什么事情,是对程序的抽象。使用DBMS_SCHEDULER.CREATE_PROGRAM创建program
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM (
program_name => ¨time_synchronization¨,
program_action => ¨/sbin/ntpdate 128.59.67.100¨,
program_type => ¨EXECUTABLE¨,
enabled => TRUE);
END;
/
调度现在可以支持调用外部程序了,这点很强大。
目前程序支持三种类型:
- PL/SQL块: PLSQL_BLOCK,
- 存储过程: STORED_PROCEDURE
- 外部程序: EXECUTABLE, 外部程序可以是一个shell脚本,也可以是操作系统级别的命令。
program_action: 根据program_type的不同,program_action有不同的含义。
- program_type是存储过程,就需要指定存储过程的名字;
- program_type是PL/SQL块,就需要输入完整的PL/SQL代码;
- program_type是外部程序,就需要输入script的名称或者操作系统的指令名
job表示按照指定的schedule,执行指定program,完成用户指定的工作。使用DBMS_SCHEDULER.CREATE_JOB创建job。
SQL> BEGIN
2 DBMS_SCHEDULER.CREATE_JOB (
3 job_name => ¨time_synchron¨,
4 program_name => ¨time_synchronization¨,
5 schedule_name => ¨daily_schedule¨,
6 enabled => true);
7 END;
8 /
一般情况下是如果你设定了job的enable是true的话,oracle会按照你的计划,定时调用你的job,不需要手动执行。如果临时需要马上调度job也是可以的。
exec dbms_scheduler.run_job(¨time_synchron¨);
如果觉得没有必要继续执行这个job了,可以停止该job,让oracle以后不要再继续调度了。
exec dbms_scheduler.stop_job(¨time_synchron¨);
Job 每执行一次,无论成功或失败,均会[DBA|ALL|USER]_SCHEDULER_JOB_LOG中生成一条对应的记录(前提是LOGGING_LEVEL属性值未设置为DBMS_SCHEDULER.LOGGING_OFF),job的详细信息可以通过
[DBA|ALL|USER]_SCHEDULER_JOB_RUN_DETAILS视图查看。