Neste tutorial, nós exploraremos a implementação de um cache de segundo nível em Hibernate usando NCache.
Nós configuraremos um aplicativo Java com Hibernate. Em seguida, nós configuraremos NCache como o cache de segundo nível. Finalmente, nós testaremos a implementação para ver como o cache reduz a carga do banco de dados e melhora o desempenho.
Pratiquei
Antes de mergulharmos na implementação, vamos entender os fundamentos de Hibernate, NCache e o cache de segundo nível de Hibernate.
Hibernate
Hibernate é uma ferramenta de mapeamento objeto-relacional (ORM) de código aberto para aplicações Java. Ele simplifica a interação com o banco de dados, mapeado objetos Java para tabelas de banco de dados e vice-versa.
Para melhorar o desempenho, Hibernate fornece dois níveis de cache:
1. Cache de Primeiro Nível
O cache de primeiro nível está associado à sessão Hibernate e está habilitado por padrão. Ele armazena os objetos retornados durante uma sessão, eliminando a necessidade de acessar o banco de dados várias vezes para o mesmo objeto.
O cache de primeiro nível é limitado à área de uma sessão e não é compartilhado entre sessões.
Também não é persistente e é limpo quando a sessão é fechada ou limpa explicitamente.
2. Cache de Segundo Nível
O cache de segundo nível é compartilhado entre sessões e pode ser configurado para armazenar dados no nível de aplicação. Ele reduce o número de acessos à base de dados armazenando objetos por um período maior.
O cache de segundo nível precisa ser configurado explicitamente e pode ser implementado usando vários fornecedores de cache, como NCache, Ehcache, etc.
NCache
NCache é uma solução de cache distribuído para.NET e aplicações Java. Ele fornece uma loja de dados em memória que pode ser usada para cachear dados frequentemente acessados e melhorar o desempenho da aplicação.
NCache suporta várias topologias de cache, como replicadas, particionadas e cliente em cache.
NCache pode ser usado como cache de segundo nível em Hibernate para armazenar e recuperar objetos do cache em vez de acessar o banco de dados.
Configuração do código
Vamos começar criando uma aplicação Java e configurar Hibernate para interagir com o banco de dados.
Usaremos o Maven para gerenciar dependências e construir o projeto. A aplicação terá uma classe de entidade para definir os dados e uma classe de cliente para interagir com o banco de dados.
Primeiro, vamos testar a aplicação sem cache para ver as interações com o banco de dados. Em seguida, vamos configurar o NCache como cache de segundo nível em Hibernate para cachear objetos de entidade e reduzir os acessos ao banco de dados.
Dependências
Vamos começar adicionando as dependências necessárias para Hibernate e NCache no arquivopom.xml
:
<dependencies> <!-- Hibernate dependencies --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>6.6.1.Final</version> </dependency> <!-- NCache dependencies --> <dependency> <groupId>com.alachisoft.ncache</groupId> <artifactId>ncache-hibernate</artifactId> <version>5.3.3</version> </dependency> </dependencies>
Versões mencionadas aqui podem variar com base nas últimas versões. Certifique-se de usar as versões apropriadas para o seu projeto.
Classe de Entidade
Agora, vamos criar uma classe de entidade para representar os dados que queremos cachear. Vamos definir uma simples classe Cliente
com campos id
e nome
:
@Entity @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "CustomerRegion") public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // getters and setters }
A classe Cliente
está anotada com @Entity
e @Cacheable
para defini-la como uma entidade cacheável. Ela tem um campo id
anotado com @Id
e @GeneratedValue
para gerar identificadores únicos automaticamente.
Nós também usamos a anotação @Cache
para especificar a estratégia de cache e o namespace para a entidade.
NONSTRICT_READ_WRITE
diz ao Hibernate para atualizar o cache quando dados são lidos ou escritos com consistência eventual.
O atributo region
especifica o namespace de cache onde os dados serão armazenados.
Vamos configurar o NCache para usar este namespace para armazenar os dados em cache.
Configuração do Hibernate
Nós precisamos configurar o Hibernate para interagir com o banco de dados e habilitar o cache.
Vamos criar um arquivo hibernate.cfg.xml
no diretório src/main/resources
com a seguinte configuração:
<?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> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.dialect">org.hibernate.dialect.Oracle12cDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> </session-factory> </hibernate-configuration>
Neste arquivo de configuração, especificamos detalhes de conexão com o banco de dados, dialeto e configurações de cache. Usamos o Oracle como o banco de dados e configuramos o Hibernate para atualizar o esquema automaticamente.
Classe de Cliente
Vamos criar uma classe de cliente para interagir com o banco de dados e testar o mecanismo de cache. Podemos escrever uma classe main
para salvar e recuperar objetos Customer
usando Hibernate:
public class HibernateClient { public static void main(String[] args) { SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setName("John Doe"); session.save(customer); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); Customer retrievedCustomer = session.get(Customer.class, customer.getId()); System.out.println("Retrieved Customer: " + retrievedCustomer.getName()); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); retrievedCustomer = session.get(Customer.class, customer.getId()); System.out.println("Retrieved Customer: " + retrievedCustomer.getName()); transaction.commit(); session.close(); } }
Nesta classe de cliente, criamos uma SessionFactory
usando a configuração do Hibernate e abrimos uma sessão para interagir com o banco de dados. Salvemos um objeto Customer
no banco de dados e o recuperamos usando o id
.
Então, chamamos o método retrieveCustomer
duas vezes em duas sessões separadas para ver as interações com o banco de dados sem cache.
Vamos observar que o banco de dados é acessado duas vezes para recuperar o mesmo objeto:
Como podem ver, a consulta do Hibernate é executada duas vezes.
Configurando o Servidor NCache
Para usar o NCache como o cache de segundo nível no Hibernate, precisamos configurar um servidor NCache e configurá-lo para armazenar os dados em cache.
O NCache fornece uma solução de cache distribuído que pode ser instalada em servidores Windows e Linux. Vamos criar um cluster de cache usando o NCache e o configurar. Assim que o cluster de cache for configurado, podemos conectá-lo à nossa aplicação Java.
Habilitando o NCache como provedor de cache de segundo nível no Hibernate
Uma vez que o servidor NCache estiver configurado, podemos configurar o Hibernate para usar o NCache como provedor de cache de segundo nível. Atualizaremos o arquivo de configuração do Hibernate e especificaremos as configurações de cache para habilitar o cache.
Habilitando as Regiões de Cache
Vamos atualizar as configurações de cache no arquivo hibernate.cfg.xml
para habilitar o NCache como provedor de cache de nível dois:
<hibernate-configuration> <session-factory> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class">com.alachisoft.ncache.NCacheRegionFactory</property> ... </session-factory> </hibernate-configuration>
Aqui, definimos a propriedade hibernate.cache.use_second_level_cache
como true
para habilitar o cache de nível dois. Também especificamos a propriedade hibernate.cache.region.factory_class
para usar a NCacheRegionFactory
, uma implementação da JCacheRegionFactory
, como provedor de cache.
Configurando as Propriedades do NCache
O NCache fornece um conjunto de propriedades para configurar as definições de cache no Hibernate. Podemos especificá-las no arquivo ncache-hibernate.xml
:
<configuration> <application-config application-id="myapp" enable-cache-exception="true" default-region-name="DefaultRegion" key-case-sensitivity="false"> <cache-regions> <region name="CustomerRegion" cache-name="demoCache" priority="AboveNormal" expiration-type="Sliding" expiration-period="8"/> <region name="DefaultRegion" cache-name="demoCache" priority="default" expiration-type="None" expiration-period="0"/> </cache-regions> <database-dependencies> <dependency entity-name="hibernator.BLL.Customer" type="oledb" sql-statement="SELECT CustomerID FROM Customers WHERE CustomerID ='?';" cache-key-format="Customers#[pk]" connection-string="Provider=SQLOLEDB;Data Source=20.200.20.40,1433;Initial Catalog=Northwind;User ID=john;Password=1234;"/> </database-dependencies> </application-config> </configuration>
Neste arquivo de configuração, definimos a região de cache CustomerRegion
com o nome do cache, a prioridade, o tipo de expiração e o período de expiração. Configuramos o expiration-type
para Sliding
com um período de expiração de 8
segundos. Isso significa que os dados em cache expirarão após 8 segundos de inatividade e serão removidos do cache.
Adicionalmente, definimos uma DefaultRegion
com configurações padrão para outras entidades que não têm uma região de cache específica. Isso serve como uma região de fallback para entidades que não estão explicitamente configuradas.
Haveria múltiplas regiões de cache que nos permitem definir diferentes configurações de cache para diferentes entidades com base em suas exigências.
Agora, definimos uma dependência de banco de dados para a entidade Customers
. Isso é usado para manter o cache sincronizado com o banco de dados e atualizar/remover os dados em cache quando há mudanças no banco de dados.
Nós especificamos a instrução SQL para recuperar o CustomerID
da tabela Customers
e a string de conexão para se conectar ao banco de dados.
O formato da chave de cache especifica como a chave de cache é gerada com base na chave primária da entidade.
Testando
Como nós configuramos o NCache como o cache de nível dois em Hibernate, vamos testar a aplicação para ver como o cache melhora o desempenho. Vamos executar a classe de cliente novamente e observar as interações com o banco de dados com o cache habilitado.
Quando nós executarmos a classe de cliente, verificaremos que a primeira chamada para recuperar o objeto Customer
atinge o banco de dados para buscar os dados. No entanto, a segunda chamada para recuperar o mesmo objeto o obterá do cache em vez de atingir o banco de dados novamente. Isto demonstra como o cache reduz o carregamento do banco de dados e melhora o desempenho através do serviço de dados do cache.
Benefícios de Usar o NCache Com Hibernate
Usar o NCache como o cache de nível dois em Hibernate fornece vários benefícios:
- Performance melhorada: O NCache fornece um armazenamento em memória rápido para dados em cache, reduzindo a latência e melhorando a throughput. Ele também fornece operações assíncronas para atualizar o cache em segundo plano, reduzindo o impacto no desempenho do aplicativo.
- Escalabilidade: À medida que o aplicativo escale, o NCache pode escalar horizontalmente para manter grandes quantidades de dados e solicitações de usuário. Ele pode ser implantado em um clúster e suporta recursos como replicação de cache e particionamento para distribuir a carga.
- Flexibilidade: O NCache fornece varias topologias de cache e configurações para atender a diferentes exigências de aplicativos. Além disso, devido ao uso de regiões de cache, diferentes entidades podem ter configurações de cache diferentes conforme suas necessidades. Isso permite um controle granular sobre o comportamento de cache.
- Sincronização: O NCache oferece a opção de sincronização com o banco de dados para manter o cache sincronizado com o banco de dados. Isso garante que os dados em cache estejam atualizados e refletem as últimas mudanças feitas no banco de dados.
Sumário
Neste tutorial, nós exploramos a implementação the cache de nível dois em Hibernate usando o NCache para aplicações Java.
Começamos entendendo os fundamentos de Hibernate, NCache, e o cache de nível dois do Hibernate. Em seguida, nós configuramos um aplicativo Java com Hibernate e configuramos o NCache como cache de nível dois. Finalmente, nós testamos a implementação para ver como o cache melhora o desempenho, reduzindo chamadas ao banco de dados e servindo dados do cache.
Ao usar o NCache com Hibernate, os desenvolvedores podem melhorar o desempenho, a escalabilidade e a confiabilidade das suas aplicações, aproveitando o poder do cache distribuído. O NCache fornece uma solução de cache robusta que integra-se com facilidade com Hibernate e outros frameworks Java, tornando-se uma escolha ideal para o cache de dados em aplicações Java.
Source:
https://dzone.com/articles/implement-hibernate-second-level-cache-with-ncache