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_PROC job: '||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)