Nos últimos tempos tenho trabalhado com jobs em base de dados Oracle.
Mesmo que a base de dados utilizada fosse a 10g é ainda utilizado o DBMS_JOB
. Recentemente li o [1] e descobri o DBMS_SCHEDULER
.
Dou dois
exemplos de dificuldades que senti com o DBMS_JOB
:
- definir o intervalo de execução: fraca legibilidade, demasiado código para conseguir o agendamento desejado;
- configurar o deploy de um job: apenas um campo númérico identifica univocamente o job na lista.
Neste post vou falar sobre o segundo ponto: o deploy de um job.
Oracle 9i: o DBMS_JOB
Na versão 9i a gestão de jobs é feita com o package DBMS_JOB
.
Eis o script de deploy mais simples:
DECLARE V_JOB NUMBER; BEGIN DBMS_JOB.SUBMIT( JOB => V_JOB, WHAT => 'BEGIN MY_PKG.MY_EXEC_PROC; END;', NEXT_DATE => SYSDATE); commit; dbms_output.put_line('Created MY_PKG.MY_EXEC_PROCjob: '||v_job); END; /
Este script tem o seguinte problema: se executarmos o script outra vez o resultado vai ser a criação de outro job igual ao primeiro. Este foi alias a situação com que me deparei de início: a base de dados tinha dezenas de jobs a realizar a mesma tarefa!
Posto o problema de apenas o campo job
(do tipo número) identificar univocamente o job, utilizei o campo what
para o identificar. Criei o seguinte script de deploy:
DECLARE V_JOB NUMBER; V_WHAT VARCHAR2(100) := 'BEGIN MY_PKG.MY_EXEC_PROC; END;'; V_NEXT_DATE DATE := SYSDATE; BEGIN dbms_output.put_line('Deleting all MY_PKG.MY_EXEC_PROC jobs:'); FOR jobs_to_delete IN ( SELECT job FROM user_jobs WHERE what like V_WHAT ) LOOP dbms_output.put_line('...removing MY_PKG.MY_EXEC_PROC job ' || jobs_to_delete.job); dbms_job.remove(jobs_to_delete.job); END LOOP; dbms_output.put_line('Deleted all MY_PKG.MY_EXEC_PROC jobs.'); commit; DBMS_JOB.SUBMIT(V_JOB, V_WHAT, V_NEXT_DATE); commit; dbms_output.put_line('Created MY_PKG.MY_EXEC_PROC job: '||v_job); END; /
Reparar no loop para resolver o caso de fazerem deploy do mesmo job.
Este script não resolve outro problema: se numa fase de desenvolvimento alterarmos o what
do job não iremos remover os jobs antigos – claro que esta situação tem pouco impacto com algum controlo regular sobre o que existe na base de dados.
Este script poderia ser isolado num procedimento com a assinatura
DEPLOY_JOB( job OUT BINARY_INTEGER, what IN VARCHAR2, next_date IN DATE DEFAULT sysdate, interval IN VARCHAR2 DEFAULT 'null', job_name IN VARCHAR2); -- 'job_name' serve apenas para dbms_output
que não é mais do que estender as funcionalidades do DBMS_JOB.SUBMIT
.
Oracle 10g: o DBMS_SCHEDULER
Mas eis que a 10g apresenta uma solução muito mais completa: o package DBMS_SCHEDULER
.
Eis o novo script de deploy proposto
DECLARE V_JOB_NAME VARCHAR2(100) := 'MY_PKG_MY_EXEC_PROC'; BEGIN DBMS_SCHEDULER.DROP_JOB( job_name => V_JOB_NAME ); DBMS_SCHEDULER.CREATE_JOB( job_name => V_JOB_NAME, job_type => 'PLSQL_BLOCK', job_action => 'BEGIN MY_PKG.MY_EXEC_PROC; END;'); start_date => SYSDATE ); END; /
job_name
This attribute specifies the name of the job and uniquely identifies the job.
The name has to be unique in the SQL namespace. For example, a job cannot have the same name as a table in a schema.
If job_name is not specified, an error is generated. If you want to have a name generated by the Scheduler, you can use the GENERATE_JOB_NAME procedure to generate a name and then use the output in the CREATE_JOB procedure. The GENERATE_JOB_NAME procedure call generates a number from a sequence, which is the job name. You can prefix the number with a string. The job name will then be the string with the number from the sequence appended to it.
Além do job ter um identificador descritivo, não é apenas único na lista de jobs mas também em todo o schema.
E com o DBMS_SCHEDULER.GENERATE_JOB_NAME
nem precisariamos de nos preocupar com o nome do job, similar ao DBMS_JOBS
.
E óptimo disponibilizar a geração de valores para job_name
com prefixo, muito útil em aplicações que geram internamente jobs e que teriam de implementar esta geração do nome.
Nota importante: ao contrário do DBMS_JOB.SUBMIT
, o DBMS_SCHEDULER.CREATE_JOB
faz commit, tentando ser similar a um statement DDL.
Leituras
- [1] Oracle Database Administrator’s Guide 10g Release 1 (http://www.oracle.com)
- [2] PLSQL Packages and Types Reference 10g Release 1 (http://www.oracle.com)