Bem-vindo ao Tutorial do Exemplo de Cache de Primeiro Nível do Hibernate. Recentemente, analisamos a arquitetura do Hibernate, o mapeamento do Hibernate e como usar o HQL para executar consultas SQL de maneira orientada a objetos. Hoje, vamos explorar um dos aspectos importantes do Hibernate – o Cache do Hibernate.
Cache do Hibernate
O Cache do Hibernate pode ser muito útil para obter um desempenho rápido da aplicação, se usado corretamente. A ideia por trás do cache é reduzir o número de consultas ao banco de dados, diminuindo assim o tempo de processamento da aplicação. O Hibernate vem com diferentes tipos de Cache:
- Primeiro Nível de Cache: O cache de primeiro nível do Hibernate está associado ao objeto Session. O cache de primeiro nível do Hibernate é ativado por padrão e não há como desativá-lo. No entanto, o Hibernate fornece métodos através dos quais podemos excluir objetos selecionados do cache ou limpar o cache completamente. Qualquer objeto armazenado em cache em uma sessão não será visível para outras sessões e, quando a sessão for fechada, todos os objetos em cache também serão perdidos.
- Segundo Nível de Cache: O cache de segundo nível do Hibernate é desativado por padrão, mas podemos ativá-lo através da configuração. Atualmente, o EHCache e o Infinispan fornecem implementação para o cache de segundo nível do Hibernate e podemos usá-los. Investigaremos isso no próximo tutorial sobre o cache do Hibernate.
- Cache de Consulta: O Hibernate também pode armazenar em cache o conjunto de resultados de uma consulta. O cache de consulta do Hibernate não armazena o estado das entidades reais no cache; ele armazena apenas valores de identificador e resultados de tipos de valor. Portanto, ele sempre deve ser usado em conjunto com o cache de segundo nível.
Exemplo de Cache do Hibernate – Primeiro Nível de Cache
Para o meu programa de exemplo de cache de primeiro nível do Hibernate, estou utilizando a mesma configuração que em Exemplo HQL, você pode conferir e configurar as tabelas e preenchê-las com dados fictícios. Vamos primeiro analisar o programa, sua saída, e depois passaremos por alguns dos pontos importantes relacionados ao Cache de Primeiro Nível do Hibernate. HibernateCacheExample.java
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateCacheExample {
public static void main(String[] args) throws InterruptedException {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
//Obter funcionário com id=1
Employee emp = (Employee) session.load(Employee.class, new Long(1));
printData(emp,1);
//Aguardar um tempo para alterar os dados no backend
Thread.sleep(10000);
//Buscar os mesmos dados novamente, verificar logs que nenhuma consulta foi executada
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
printData(emp1,2);
//Criar nova sessão
Session newSession = sessionFactory.openSession();
//Obter funcionário com id=1, notice the logs for query
Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
printData(emp2,3);
//INÍCIO: exemplo de evicção para remover objeto específico do cache de primeiro nível do hibernate
//Obter funcionário com id=2, primeira vez, portanto consulta nos logs
Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
printData(emp3,4);
//remover o objeto funcionário com id=1
session.evict(emp);
System.out.println("Session Contains Employee with id=1?"+session.contains(emp));
//como o objeto foi removido do cache de primeiro nível, você verá consulta nos logs
Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
printData(emp4,5);
//este objeto ainda está presente, então você não verá consulta nos logs
Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
printData(emp5,6);
//FIM: exemplo de evicção
//INÍCIO: exemplo de limpeza para remover tudo do cache de primeiro nível
session.clear();
Employee emp6 = (Employee) session.load(Employee.class, new Long(1));
printData(emp6,7);
Employee emp7 = (Employee) session.load(Employee.class, new Long(2));
printData(emp7,8);
System.out.println("Session Contains Employee with id=2?"+session.contains(emp7));
tx.commit();
sessionFactory.close();
}
private static void printData(Employee emp, int count) {
System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
}
}
Ao executarmos o exemplo acima, a saída contém muitas informações relacionadas ao Hibernate. Mas estamos principalmente interessados na saída específica do nosso código e nas consultas executadas pelo Hibernate para carregar os dados. O trecho de saída se parece com o seguinte.
Hibernate Configuration loaded
Hibernate serviceRegistry created
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
1:: Name=Pankaj, Zipcode=95129
2:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
3:: Name=PankajK, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
4:: Name=David, Zipcode=95051
Session Contains Employee with id=1?false
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
5:: Name=Pankaj, Zipcode=95129
6:: Name=David, Zipcode=95051
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
7:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
8:: Name=David, Zipcode=95051
Session Contains Employee with id=2?true
Pontos Importantes do Cache de Primeiro Nível no Hibernate
Pontos importantes sobre o cache de primeiro nível no Hibernate que podem ser derivados do programa acima são:
- O cache de primeiro nível do Hibernate é ativado por padrão, não são necessárias configurações para isso.
- O cache de primeiro nível do Hibernate é específico da sessão, por isso, quando obtemos os mesmos dados na mesma sessão, nenhuma consulta é feita, enquanto em outra sessão a consulta é feita para carregar os dados.
- O cache de primeiro nível do Hibernate pode conter valores antigos, como pode ser visto acima, coloquei meu programa para dormir por 10 segundos e nesse tempo atualizei o valor (nome de Pankaj para PankajK) no banco de dados, mas não foi refletido na mesma sessão. Mas em outra sessão, obtivemos o valor atualizado.
- Podemos usar o método
evict()
da sessão para remover um único objeto do cache de primeiro nível do Hibernate. - Podemos usar o método
clear()
da sessão para limpar o cache, ou seja, excluir todos os objetos do cache. - Podemos usar o método
contains()
da sessão para verificar se um objeto está presente no cache do Hibernate ou não, se o objeto for encontrado no cache, ele retorna verdadeiro, caso contrário, retorna falso. - Como o Hibernate armazena todos os objetos no cache de primeiro nível da sessão, ao executar consultas em massa ou atualizações em lote, é necessário limpar o cache em intervalos específicos para evitar problemas de memória.
Isso é tudo para o exemplo de cache do Hibernate e cache de primeiro nível, em posts futuros, vamos analisar a implementação do Cache do Segundo Nível do Hibernate – EHCache.
Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache