Fazendo cache de objetos com Hibernate - Parte I
Este artigo vai demonstrar como fazer cache de objetos com o Hibernate, para aumentar a performance de sua aplicação.
Este artigo vai demonstrar como fazer cache de objetos com o Hibernate, para aumentar a performance de sua aplicação.
O artigo está dividido em 2 partes. A primeira explica o funcionamento do cache da Session (cache simples), e a segunda será sobre o Second Level Cache (cache avançado).
Hibernate
Para rodar o exemplo deste artigo, faça o download do Hibernate 3.1.3:
Þ http://prdownloads.sourceforge.net/hibernate/hibernate-3.1.3.zip
Após fazer o download, coloque o arquivo “hibernate.jar” no classpath do seu projeto, assim como todos os outros jar’s encontrados na pasta “lib”.
Criando o POJO
Para testar o cache, vamos criar uma simples classe “Notícia”.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class
name="model.Noticia"
table="Noticia"
>
<id
name="id"
type="java.lang.Integer"
column="ID"
>
<generator class="native" />
</id>
<property
name="titulo"
type="java.lang.String"
column="titulo"
length="50"
not-null="true"
/>
</class>
</hibernate-mapping>
public class Noticia {
private Integer id;
private String titulo;
//get e set …
}
Criando a Tabela Notícia:
create table Noticia (
ID integer generated by default as identity (start with 1),
titulo varchar(50) not null,
primary key (ID))
E o arquivo hibernate.cfg.xml (Altere a URL e driver JDBC para o banco de dados de sua preferência):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- HSQLDB -->
<property name="hibernate.connection.driver_class">
org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.url">
jdbc:hsqldb:hsql://localhost/hello</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password" />
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="model/Noticia.hbm.xml" />
</session-factory>
</hibernate-configuration>
First-Level cache - Session Cache
Sempre que o Hibernate busca um objeto utilizando os métodos “load” e “get”, o resultado é armazenado no cache da Session, conhecido como first-level cache. Este cache é default no Hibernate e não pode ser desabilitado. O objeto “Session” representa uma conexão com o banco de dados, e não deve “viver” por muito tempo, desta forma é uma boa prática (recomendado) que a Session seja eliminada ao final de uma transação/requisição com o servidor. Desta forma, a conexão com o banco é fechada (ou retornada ao pool) e o cache da Session também é apagado.
O Exemplo abaixo faz uma simples busca de uma notícia com o ID=1. Note que a busca é feita 2 vezes para a Notícia, mas o Hibernate vai acessar o banco de dados apenas uma vez. Entre a 1ª e a 2ª busca, foi incluído um trecho de código que faz um UPDATE com JDBC, para atualizar o título da notícia. Porém como era esperado, o Hibernate manteve a Notícia no cache da Session, e o título da 2ª busca ainda é uma informação antiga.
Ao rodar o exemplo, vamos supor que existe uma notícia na tabela com o ID = 1.
public class Teste1 {
public static void main(String[] args) throws Exception {
SessionFactory sessionFactory =
new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
//Recupera a notícia do banco. Insere no cache da Session
System.out.println("1 - pre session.get");
Noticia n = (Noticia) session.get(Noticia.class, new Integer(1));
System.out.println("1 - pos session.get");
System.out.println(n.getTitulo());
//Atualiza a tabela usando JDBC.
Class.forName("org.hsqldb.jdbcDriver");
Connection conn = DriverManager.getConnection
("jdbc:hsqldb:hsql://localhost/hello","sa","");
Statement stmt = conn.createStatement();
stmt.executeUpdate("update noticia set titulo = 'novo titulo'");
//Tire o comentário para remover a Notícia do cache da Session
//session.evict(n);
//A segunda busca vai imprimir o título antigo da notícia.
System.out.println("2 - pre session.get");
n = (Noticia) session.get(Noticia.class, new Integer(1));
System.out.println("2 - pos session.get");
System.out.println(n.getTitulo());
t.commit();
session.close();
}
}
Saída:
1 - pre session.get
Hibernate: select noticia0_.ID as ID0_0_, noticia0_.titulo as titulo0_0_, noticia0_.texto as texto0_0_ from Noticia noticia0_ where noticia0_.ID=?
1 - pos session.get
Titulo antigo
2 - pre session.get
2 - pos session.get
Titulo antigo
O texto “Título antigo” apareceu duas vezes, como era esperado.
Note que está comentado a linha com o código: “session.evict(n);”. O método evict(object) da classe Session elimina o objeto do cache, fazendo com que o Hibernate consulte o banco de dados todas as vezes que precisar de determinada informação. Faça o teste!
Entendendo o First-Lavel cache
Sempre que uma nova Session é aberta, uma nova conexão com o servidor é realizada e um novo cache é criado. Quando a Session for fechada, o seu cache correspondente também é eliminado. O cache de uma Session não interfere em outra Session.
Para comprovar isto, altere o código anterior, para fechar a Session atual, e abrir uma nova antes de fazer a segunda consulta.
//1ª consulta…
//JDBC com update…
t.commit();
session.close();//fecha a 1ª session (fecha conexão e elimina o cache)
session = sessionFactory.openSession(); //cria uma nova session
t = session.beginTransaction();
//nesta session os dados serão consultados do banco de dados
//2ª consulta…
O resultado da execução deste código pode ser visualizado abaixo:
1 - pre session.get
Hibernate: select noticia0_.ID as ID0_0_, noticia0_.titulo as titulo0_0_, noticia0_.texto as texto0_0_ from Noticia noticia0_ where noticia0_.ID=?
1 - pos session.get
Titulo Antigo
2 - pre session.get
Hibernate: select noticia0_.ID as ID0_0_, noticia0_.titulo as titulo0_0_, noticia0_.texto as texto0_0_ from Noticia noticia0_ where noticia0_.ID=?
2 - pos session.get
Novo titulo
Note que o Hibernate fez 2 consultas no banco. E que o título da notícia foi atualizano na segunda busca.
Lembre-se de que outra maneira de eliminar um objeto da cache (sem fechar a Session) é chamando o método “session.evict(obj)”.
Conclusão
Neste artigo foi explicado como funciona o first level cache do Hibernate, o qual armazena os objetos para a Session corrente.
Este cache é muito simples para ser utilizado em aplicações Web, onde geralmente a cada requisição ao servidor, uma nova Session é criada. Então fica a pergunta, como utilizar cache de objetos mesmo Sessions (conexões) diferentes?
Para isto existe o Second-Level cache, que é uma estratégia de cache um pouco mais agressiva e eficiente, onde alguns frameworks como o EHCache e OSCache são utilizados. Este cache será explicado na 2ª parte do artigo.

Space do autor

Estudo comparativo entre banco de dados IBM Informix e Microsoft SQL


1
1
Conheça os planos de créditos DevMedia e visualize esse post agora mesmo!