пятница, 6 июня 2014 г.

dbms_scheduler

Краткие выводы:
1. Commit не только не нужен, но и делается внутри run_job
2. Если мы хотим сохдать job, который будет запускаться без лишних телодвижений, то в create_job надо указывать enabled => true
3. Если мы не указали enabled = true, то job можно запустить руками, но при этом user_scheduler_jobs.run_count не инкрементируется. Если enabled = true, то инкрементируется и при запуске руками
4. Удобно задавать интервалы запуска не через даты (хотя это тоже возможно), а через выражения, например 'FREQ=MINUTELY;INTERVAL=2'
5. Если job занимает больше времени, чем интервал, то он будет выполняться постоянно, причем в таблице user_scheduler_jobs дата следующего запуска была меньше даты последнего
6. Дата следующего запуска отсчитывается от даты начала предыдущего, а не от конца
7. max_failures можно установить только через set_attribute. Если он NULL, то джоб никогда не ломается.

Код

CREATE TABLE job_test(a NUMBER PRIMARY KEY, dt DATE DEFAULT SYSDATE); create SEQUENCE job_test_seq; -- 1. Джоб выполняем 1 раз. BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'insert into job_test(a) values(job_test_seq.nextval);' ); END; / BEGIN insert into job_test(a) values(-2); dbms_scheduler.run_job(job_name => 'a_job', use_current_session => TRUE); END; / -- Вывод Commit не только не нужен, но и делает его явно, вне зависимости от второго параметра -- 2. Джоб выполняем раз в минуту, час, день BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'insert into job_test(a) values(job_test_seq.nextval);', repeat_interval => 'FREQ=MINUTELY', /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ENABLED => TRUE ); END; / -- надо указывать enabled=true, иначе не запустится -- Без enabled запускается только руками, причем в user_scheduler_jobs запуск руками в колонке RUN_COUNT не отражается BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'insert into job_test(a) values(job_test_seq.nextval);', start_date => SYSDATE + 1/24/60, repeat_interval => 'FREQ=MINUTELY' /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ); END; / BEGIN dbms_scheduler.run_job(job_name => 'a_job', use_current_session => TRUE); END; / -- А так и run_count будет инкрементироваться BEGIN dbms_scheduler.enable(name => 'a_job'); END; / -- А как запускать каждые 2 минуты через интервал BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'insert into job_test(a) values(job_test_seq.nextval);', repeat_interval => 'FREQ=MINUTELY;INTERVAL=2', /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ENABLED => TRUE ); END; / BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'dbms_lock.sleep(10); insert into job_test(a) values(job_test_seq.nextval);', repeat_interval => 'FREQ=SECONDLY;INTERVAL=3', /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ENABLED => TRUE ); END; / -- Прибавляется ли дата к концу BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'dbms_lock.sleep(10); insert into job_test(a) values(job_test_seq.nextval);', repeat_interval => 'FREQ=MINUTELY', /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ENABLED => TRUE ); END; / -- Вывод - дата отсчитывается от начала запуска -- max_failures BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'insert into job_test(a) values(1);', repeat_interval => 'FREQ=secondly', /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ENABLED => TRUE ); END; / -- по-умолчанию выполняется вечность -- попробуем поставить -- Делается только через set_attribute BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'PLSQL_BLOCK', job_action => 'insert into job_test(a) values(1);', repeat_interval => 'FREQ=secondly', /*"YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | "HOURLY" | "MINUTELY" | "SECONDLY"*/ ENABLED => TRUE ); dbms_scheduler.set_attribute(name => 'a_job', attribute => 'max_failures', value => 100); END; / --Можно ли процедуру засунуть в пакет для типа STORED_PROCEDURE create or replace package tst_job is PROCEDURE tst_job; end tst_job; / create or replace package body tst_job is PROCEDURE tst_job IS BEGIN insert into job_test(a) values(job_test_seq.nextval); END; end tst_job; / BEGIN dbms_scheduler.create_job(job_name => 'a_job', job_type => 'STORED_PROCEDURE', job_action => 'sps.tst_job.tst_job', ENABLED => TRUE , auto_drop => FALSE ); END; / -- Важно -- указать auto_drop = false, иначе, без указания интервала и start_time, процедура выполняется 1 раз и сразу удаляется TRUNCATE TABLE job_test; BEGIN dbms_scheduler.drop_job('a_job'); END; / SELECT * FROM user_scheduler_jobs;