Usando quartz com o Hibernate

opa! Pessoal,

O post de hoje vou apresentar API Quartz. O objetivo é mostrar como Quartz é simples de usar. E para contexto, escolhi que criaremos um job, que terá como trabalho de popular um banco a cada X time, que nesse caso vamos usar o Hibernate para fazer esse tramapo. O Quartz nada mais é que um scheduler de jobs, que podem ser executados em momento determinados. No decorrer do post veremos mais na prática.

Lets go…

Para usar o quartz basta fazer download do jars(quartz-all.x.jar) e adicionar ao projeto. Adicione as libs do Hibernate e Banco de dados (aqui usaremos o MySQL) ao projeto também.

API QUARTZ: http://www.quartz-scheduler.org/

*Caso tenha dúvida sobre o Hibernate, veja os nossos posts na categoria.

Desenvolvimento

Para usar quartz vamos criar um package br.com.camilolopes.scheduler neste packages teremos uma classe responsavel por executar os jobs programados.

No package br.com.camilolopes.job é onde temos a classe que tem um trabalho a ser feito, que no nosso caso é persistir no banco de dados.

Package br.com.camilolopes.dao tem as configurações para o Hibernate que não está atrelado ao quartz.

Primeiro passo

É começar com a classe SchedulerJobs no package br.com.camilolopes.scheduler onde vamos definir os jobs a serem executados e o time para eles. Como esta classe será a principal, ela terá o método main.

 

package br.com.camilolopes.scheduler;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;
import br.com.camilolopes.job.PersistDB;

/*
* esse é o agendador de jobs
*/
public class SchedulerJobs {

public SchedulerJobs() {
// TODO Auto-generated constructor stub
}
public static void main(String[]args) {

//neste caso a cada 1 min
Trigger trigger = TriggerUtils.makeSecondlyTrigger(30);
trigger.setName(“jobdb”);
/*dou informacoes qual classe ele deve chamar
ou seja, o trabalho a ser feito
*/
JobDetail jobDetail = new JobDetail(“save db”, PersistDB.class);
try{
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
//info o job a ser feito e de em qto em qto tempo passando o trigger
scheduler.scheduleJob(jobDetail, trigger);
//peco para iniciar
scheduler.start();
}catch (SchedulerException e) {
e.printStackTrace();
}

}
}

Trigger = esta classe é responsável por configurar o tempo em que cada job será executado, nesse caso configuramos para a cada 30s. Veja que usamos a classe TriggerUtils. Que já possui alguns metodos implementados e não vamos precisar reiveitar a roda. Em seguida damos um nome para esse trigger.

JobDetail = é aqui que temos o job a ser executado nesse caso mandamos executar o job que está na classe PersistDB.class, veja que damos um nome para esse nome.

Scheduler = aqui onde temos uma instancia de um scheduler que será responsavel por executar o job, e como criamos uma instancia de uma factory, precisamos apenas informar o job e o tempo que ele vai ser executado nesse caso, é vai a variavel de JobDetail e o time que definimos em Trigger. Para iniciar o job chamamos o metodo start().

Na classe a serguir temos o trabalho a ser feito que é criar um usuario e chamar o método save() responsável por fazer o trabalho de persistência no banco de dados.

public class PersistDB implements Job{

@Override

publicvoid execute(JobExecutionContext arg0) throws JobExecutionException {

UsuarioQuartzDao usuariodao = new UsuarioQuartzDao();

Usuario usuario = new Usuario();

usuario.setEmail(“camilo@”);

usuario.setNome(“lopesff”);

usuario.setSenha(“123”);

usuario.setTipo(“admin”);

usuariodao.save(usuario);

System.out.println(new Date());

}

}

A classe que possui o job a ser feito precisa implementar a interface Job e colocar o trabalho dentro do metodo execute().

Classe DAO.

public class UsuarioQuartzDao extends DAO {

public void save(Usuario us){

begin();

getSession().save(us);

try{

commit();

}catch (Exception e) {

e.printStackTrace();

}}

}

Na classe acima é onde ocorre a persistencia com o banco usando o Hibernate, um detalhe que quero chamar atencao é pedi para o Hibernate criar a table e a cada vez que o job rodar ele não criar uma nova table e sim adicionar apenas os dados, para isso seu arquibo hibernate.cfg.xml deve ter um update no hb2mddl.auto como update, se não existir ele cria de forma automatica.

<property name=“hibernate.hbm2ddl.auto”>update</property>

O code completo:

<property name=“hibernate.connection.driver_class”>org.gjt.mm.mysql.Driver</property>

<property name=“hibernate.connection.password”>blog</property>

<property name=“hibernate.connection.url”>jdbc:mysql://localhost/blogleitores</property>

<property name=“hibernate.connection.username”>camilolopes</property>

<property name=“hibernate.dialect”>org.hibernate.dialect.MySQL5InnoDBDialect</property>

<property name=“hibernate.show_sql”>true</property>

<property name=“hibernate.current_session_context_class”>thread</property>

<property name=“hibernate.transaction.factory_class”>org.hibernate.transaction.JDBCTransactionFactory</property>

<property name=“hibernate.hbm2ddl.auto”>update</property>

<mapping class=“br.com.camilolopes.bean.Usuario”/>

 

Resultado

Ao executar o code, temos os resultado conforme a seguir:

 

 

Observe que o Job é executado dentro do tempo e o trabalho de persistir de fato acontece. Um fato que identifiquei é que se o job, demorar mais que o tempo configurável o próximo job, tem que aguardar o outro finalizar para iniciar o trabalho dele. Outro ponto se configurarmos o método shutdown (true) e colocar depois do método estar, assim após o termino de todos os jobs, o scheduler é “desligado” e os trabalhos não mais reiniciados. No nosso exemplo ele roda de maneira infinita.

scheduler.start();

scheduler.shutdown(true);

Vou ficando por aqui e espero que tenham gostado do post, eu tenho usado o quartz em algumas soluções no meu job e de fato é uma API excelente. Além de uma boa documentação, o fórum é bem ativo para tirar duvidas.

Abraços, see you next post. 😀

5 comentários em “Usando quartz com o Hibernate”

  1. Camilo,

    Como no meu projeto é Web e não tenho a classe com o main, só tenho que dar um “run” manual na classe SchedulerJobs e ela ficará executando infinitamente?

    Grande abraço,

  2. Olá Danilo,
    depende se vc quer q seja de forma infinita, se nao informar será, há um metodo shutdown() se configurar para true, quando o job scheduled terminar o trabalho dele, ele dará um shutdown, e nao vai reiniciar o job novamente. API do Quartz é fantastica, eu ainda nao tive a necessidade de usar o shutdown, mas ja testei, uso normalmente o daily, que o job vai executar diariamente, no horario X. e outro que será executado a cada X tempo para verificar algo.
    flw.

  3. Boa tarde Camilo,

    Estou tentando fazer algo parecido, preciso buscar dados do banco para executar uma determinada tarefa. Só que não consigo de jeito nenhum fazer o Quartz quando executa minha tarefa conectar ao banco. Poderia me ajudar?
    Ocorre o erro abaixo:

    18:15:36,255 INFO [org.hibernate.ejb.Ejb3Configuration] Could not find any META-INF/persistence.xml file in the classpath
    18:15:36,255 ERROR [org.quartz.core.JobRunShell] Job DEFAULT.EnviaEmailFamilia threw an unhandled Exception: : javax.persistence.PersistenceException: No Persistence provider for EntityManager named ccb_context
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
    at email.dao.DAOFactory.(DAOFactory.java:15)
    at email.dao.DAOFactory.getInstance(DAOFactory.java:31)
    at email.Postman.sendMessage(Postman.java:40)
    at email.Postman.execute(Postman.java:132)
    at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)

    1. olá Roger,

      A forma que você está fazendo não parecido, é diferente a parte de configuração. Mas, pela mensagem de erro, não foi possível encontrar o arquivo de persistence.xml

Deixe um comentário

O seu endereço de e-mail não será publicado.