文章目录
- 1 概述
- 1.1 基础数据准备
- 2 dbms_scheduler
- 2.1 创建
- 2.2 修改
- 2.3 删除
- 2.4 查询
- 2.5 其它操作
- 3 dbms_job
- 3.1 设置并发数
- 3.2 job 调度任务查询
- 3.3 常用操作
1 概述

1.1 基础数据准备
1 2 3 4 | CREATE TABLE test_job ( job_name VARCHAR2(30), start_date DATE ); |
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE OR REPLACE PROCEDURE p_scheduler_test AS v_sql_insert VARCHAR2(200); BEGIN -- 记录 job 信息 v_sql_insert := 'INSERT INTO test_job(job_name, start_date) VALUES(:b1, :b2)'; EXECUTE IMMEDIATE v_sql_insert USING 'TEST_JOB_NAME_02', SYSDATE; COMMIT; END; / |
2 dbms_scheduler
个人理解: scheduler 和 program 主要是为了提取 job 中重复的内容,使 job 调用写法更加简单。
| 功能 | 解释 |
|---|---|
| scheduler | 调度器。定义 scheduler 名称、起止时间、调用频率等参数 |
| program | 程序。scheduler 具体要干的事儿 |
| job | 整个调度。可以依赖 program 和 scheduler,也可以直接写入 program 和 scheduler 对应的参数 |
scheduler:调度器。定义 scheduler 名称、起止时间、调用频率等参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -- 创建 BEGIN dbms_scheduler.create_schedule(schedule_name => 'SYSTEM.TEST_SCHEDULER_NAME_01', -- 记得带属主! start_date => SYSDATE, -- 开始执行时间,默认当前 repeat_interval => 'FREQ = DAILY; INTERVAL = 1', -- 建议使用: 日历格式 end_date => SYSDATE + 7, -- 执行结束时间,默认永久 comments => '每天执行'); -- 备注信息 END; -- 查询 SELECT * FROM dba_scheduler_schedules t WHERE t.owner = 'SYSTEM'; -- 删除 BEGIN dbms_scheduler.drop_schedule(schedule_name => 'SYSTEM.TEST_SCHEDULER_NAME_01', -- 记得带属主! force => TRUE); END; |
program:程序。scheduler 具体要干的事儿
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -- 创建 BEGIN dbms_scheduler.create_program(program_name => 'SYSTEM.TEST_PROGRAM_NAME_01', program_type => 'PLSQL_BLOCK', -- 同 job_type program_action => 'INSERT INTO test_job(job_name, start_date) VALUES(''TEST_JOB_NAME_01'', SYSDATE);', enabled => TRUE, comments => 'program_name 备注信息'); END; -- 查询 SELECT * FROM dba_scheduler_programs t WHERE t.owner = 'SYSTEM'; -- 删除 BEGIN dbms_scheduler.drop_program(program_name => 'SYSTEM.TEST_PROGRAM_NAME_01', force => TRUE); END; |
job:整个调度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | -- 创建,有两种方式 -- 1.直接创建 -- 2.scheduler + program BEGIN dbms_scheduler.create_job(job_name => 'SYSTEM.TEST_JOB_NAME_02', program_name => 'SYSTEM.TEST_PROGRAME_NAME_01', schedule_name => 'SYSTEM.TEST_SCHEDULE_NAME_O1', enabled => TRUE, comments => 'program + schedule 方式创建 job'); END; -- 查询 SELECT * FROM dba_scheduler_jobs t WHERE t.owner = 'SYSTEM'; SELECT to_char(t.log_date, 'YYYY-MM-DD HH24:MI:SS'), t.* FROM dba_scheduler_job_log t WHERE t.owner = 'SYSTEM' ORDER BY t.log_date DESC; -- 删除 BEGIN dbms_scheduler.drop_job(job_name => 'SYSTEM.TEST_JOB_NAME_02', force => force); END; |
2.1 创建
拥有 create job 权限的用户才能创建定时任务:
1 | SELECT * FROM dba_sys_privs t WHERE t.privilege LIKE '%JOB' ORDER BY 1; |
- 缺省属主的情况下,job 会被创建在当前的 schema 下,并且是没有激活的;
- 如果要使 job 已创建就自动激活,需要显式的设置 enabled 属性为 true
- 创建 job 有以下两种方式
| 创建 job 的方式 | 解释 |
|---|---|
| dbms_scheduler.create_job | 直接创建 job |
| dbms_scheduler.create_schedule + dbms_scheduler.create_program | 引用 scheduler + program |
方式1:dbms_scheduler.create_job
- 可通过 PL/SQL 提示(或按 F6 提示)进行查看,具体的可以鼠标左键点进去,查看包头说明
[]: 可选项 ,其它:必填项- 其它过程查看方式相同,就不再赘叙

示例:每分钟执行一次 job,执行 3 次后,自动删除 job
若设置了
end_date ,到达 结束时间时,任务会被自动删除
若未设置end_date ,那么 任务会一直执行
1 2 3 4 5 6 7 8 9 10 11 12 13 | DECLARE BEGIN dbms_scheduler.create_job(job_name => 'SYSTEM.TEST_JOB_NAME_01', job_type => 'PLSQL_BLOCK', job_action => 'INSERT INTO test_job(job_name, start_date) VALUES(''TEST_JOB_NAME_01'', SYSDATE);', start_date => SYSDATE, repeat_interval => 'freq = minutely; interval = 1', end_date => SYSDATE + 3 / (24 * 60), enabled => TRUE, comments => '每 1 分钟打印当前时间'); END; / |
参数说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 1. job_name: job 名称 2. job_type: job 类型, (1) STORED_PROCEDURE: 存储过程 (2) PLSQL_BLOCK: PL/SQL 块 (3) EXECUTABLE: 外部程序(可以是一个 shell 脚本,也可以是操作系统级别的指令) 3. job_action: job 动作. 根据不同的 job_type, job_action 有不同的含义 (1) 如果 job_type 指定的是 存储过程,就需要指定存储过程名 (2) 如果 job_type 指定的是 PL/SQL 块,就需要输入完整的 PL/SQL 代码 (3) 如果 job_type 指定的是 外部程序, 就需要输入脚本名称或操作系统的指定名称 4. repeat_interval: 重复间隔(频率) (1) freq: 重复的类型 YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY 年, 月, 周, 日, 小时, 分钟, 秒 (2) interval: 重复的间隔,默认为 1, 取值范围 1-99 'freq = weekly; interval = 1': 每周执行一次 5. enabled: 指定 job 创建完毕时, 是否自动激活 6. comments: 对于 job 的简单说明 |
执行日志:
1 2 3 4 5 | SELECT to_char(t.log_date, 'YYYY-MM-DD HH24:MI:SS'), t.* FROM dba_scheduler_job_log t WHERE t.owner = 'SYSTEM' -- 测试用户 AND t.LOG_DATE >= DATE '2020-06-19' -- 测试时间 ORDER BY t.log_date DESC; |

方式2:dbms_scheduler.create_schedule + dbms_scheduler.create_program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | BEGIN dbms_scheduler.create_schedule(schedule_name => 'SYSTEM.TEST_SCHEDULE_NAME_O1', -- 唯一 start_date => SYSDATE, -- 开始执行时间,默认当前 repeat_interval => 'FRQE = MINUTELY; INTERVAL = 1', end_date => SYSDATE + 7, -- 执行结束时间,默认永久 comments => '每天执行'); -- 备注信息 END; / BEGIN dbms_scheduler.create_program(program_name => 'SYSTEM.TEST_PROGRAME_NAME_01', program_type => 'STORED_PROCEDURE', -- 同 job_type program_action => 'SYSTEM.P_SCHEDULER_TEST', enabled => TRUE, comments => '测试01'); END; / BEGIN dbms_scheduler.create_job(job_name => 'SYSTEM.TEST_JOB_NAME_02', program_name => 'SYSTEM.TEST_PROGRAME_NAME_01', -- 引用 program schedule_name => 'SYSTEM.TEST_SCHEDULE_NAME_O1', -- 引用 schedule enabled => TRUE, comments => 'program + schedule 方式创建 job'); END; / |
2.2 修改
- 活动的 job 才能被修改(已完成的改不了哦)
1 2 3 4 5 | BEGIN dbms_scheduler.set_attribute(NAME => 'SYSTEM.TEST_JOB_NAME_01', attribute => 'end_date', VALUE => SYSDATE + 2 / (24 * 60)); END; |
运行结果:(因为这个任务已经完成了,所以无法被修改)

验证:修改执行中 job 的属性(如:end_date)
先清空表 test_job
TRUNCATE TABLE test_job; ,便于测试观察
1 2 3 4 5 6 7 8 9 10 11 12 13 | DECLARE BEGIN dbms_scheduler.create_job(job_name => 'SYSTEM.TEST_JOB_NAME_01', job_type => 'PLSQL_BLOCK', job_action => 'INSERT INTO test_job(job_name, start_date) VALUES(''TEST_JOB_NAME_01'', SYSDATE);', start_date => SYSDATE, repeat_interval => 'freq = minutely; interval = 1', -- end_date => SYSDATE + 3 / (24 * 60), -- 注释此处,方便修改 enabled => TRUE, comments => '每 1 分钟打印当前时间'); END; / |
等个几分钟,再执行上述修改属性代码:(dbms_scheduler.set_attribute)后测试结果:
1 2 3 4 5 6 7 | SELECT * FROM test_job; SELECT to_char(t.log_date, 'YYYY-MM-DD HH24:MI:SS'), t.* FROM dba_scheduler_job_log t WHERE t.owner = 'SYSTEM' -- 测试用户 AND t.LOG_DATE >= TO_DATE('2020/6/19 8:16:05', 'YYYY/MM/DD hh24:mi:ss') -- 测试时间 ORDER BY t.log_date DESC; |

2.3 删除
1 2 3 4 5 6 | DECLARE BEGIN -- 其它的删除类似,如 dbms_scheduler.drop_xxx(); dbms_scheduler.drop_job(job_name => '', force => TRUE); END; / |
2.4 查询
1 2 3 4 | SELECT * FROM dba_scheduler_jobs t; -- 查看 job 信息 (其中 AUTO_DROP: 是否自动删除) SELECT * FROM dba_scheduler_job_log t; -- 日志 SELECT * FROM dba_scheduler_job_run_details t; -- 运行日志 SELECT * FROM dba_scheduler_running_jobs t; -- 正在运行的 job |
2.5 其它操作
1 2 3 4 5 6 7 8 9 10 11 | -- 立即运行 job dbms_scheduler.run_job('job_name'); -- 立即停止 job dbms_scheduler.stop_job('job_name',FORCE); -- 启用 job dbms_scheduler.enable('job_name'); -- 禁用 job dbms_scheduler.disable('job_name', FORCE); |
3 dbms_job
3.1 设置并发数
1. 查看数据库中定时任务的最多并发数
1 | > show parameter job_queue_processes |
2. 设置数据库中定时任务的最多并发数(比如:10)
1 | > alter system set job_queue_processes = 10 |
3.2 job 调度任务查询
1 2 3 4 5 | SELECT t.* FROM dba_jobs t; -- 所有的 job SELECT t.* FROM all_jobs t; -- 当前用户所有能够访问的 job SELECT t.* FROM user_jobs t; -- 当前用户下 SELECT t.* FROM dba_jobs_running t; -- 执行中的 job |
interval 参数说明:
1 2 3 4 5 6 7 8 9 10 11 12 | 1. 每天运行一次 'SYSDATE + 1' 2. 每小时运行一次 'SYSDATE + 1/24' 3. 每 10 分钟运行一次 'SYSDATE + 10/(24*60)' 4. 每 30 秒运行一次 'SYSDATE + 30/(24*60*60)' 5. 每隔一个星期运行一次 'SYSDATE + 7' 6. 不再运行该任务并删除 NULL 7. 每天午夜 12 点 'TRUNC(SYSDATE + 1)' 8. 每天早上 8 点 30 分 'TRUNC(SYSDATE + 1) + (8*60+30)/(24*60)' 9. 每星期二中午 12 点 'NEXT_DAY(TRUNC(SYSDATE), "TUSDAY") + 12/24' 10. 每个月第一天的午夜 12 点 'TRUNC(LAST_DAT(SYSDATE) + 1)' 11. 每个季度最后一天的晚上 11 点 'TRUNC(ADD_MONTHS(SYSDATE + 2/24, 3), "Q")' - 1/24 12. 每周六和周日早上 6 点 10 分 'TRUNC(LEAST(NEXT_DAY(SYSDATE, "SATURDAY"), NEXT_DAY(SYSDATE), "SUNDAY")) + (6*60+10)/(24*60)' |
3.3 常用操作
- 道理和 dbms_scheduler 相同,而且 dbms_job 已不推荐使用,故此处知晓即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1. 提交 job dbms_job.submit(); 2. 启动运行 job dbms_job.run(); 3. 删除 job: dbms_job.remove(job); 4. 修改要执行的操作 job dbms_job.what(job, what); 5. 修改下次执行时间 dbms_job.next_date(job, next_date) 6. 修改时间间隔 dbms_job.interval(job, interval); 7. 停止 job dbms_job.broken(job, broken, next_date); |