Por que você precisa de um cache de consulta

Vamos reescrever nosso exemplo com a obtenção de funcionários em HQL:

Employee director1 = session.createQuery("from Employee where id = 4").uniqueResult();
Employee director2 = session.createQuery("from Employee where id = 4").uniqueResult();

assertTrue(director1 != director2);

Os resultados dessas consultas não são armazenados pelo cache de primeiro ou segundo nível.

É exatamente aqui que o cache de consulta pode ser usado . Ele também está desabilitado por padrão. Para ativá-lo, adicione a seguinte linha ao arquivo de configuração:

<property name="hibernate.cache.use_query_cache" value="true"/>

Mas esta é apenas metade da solução. Habilitamos o cache de consulta, mas também precisamos especificar quais resultados de consulta queremos armazenar em cache. Isso deve ser escrito na Consulta:

Query query = session.createQuery("from Employee where id = 4");
query.setCacheable(true);
Employee director1 = query.uniqueResult();

O cache de consulta é semelhante a um cache de segundo nível. Mas, diferentemente dele, aqui a chave para os dados do cache não é o identificador do objeto, mas o conjunto de parâmetros de consulta. E os próprios dados são os identificadores dos objetos que correspondem aos critérios da consulta. Portanto, é racional usar esse cache com o cache de segundo nível.

Limpando o cache

Uma das tarefas importantes ao trabalhar com um cache é garantir que os objetos armazenados em cache sejam alterados e removidos do cache (ou atualizados). O Hibernate faz isso muito bem. Às vezes até parece que ele é guiado pela regra “limpe o cache em qualquer situação incompreensível”.

Digamos que você queira atualizar os dados do usuário via HQL:

Query query = session.createQuery("update Employee set name=’Alex’ where id = 4")
query. executeUpdate();

O Hibernate não pode saber exatamente o que mudou no banco de dados, mas sabe que você está alterando um objeto Employee. Portanto, após executar esta consulta, o Hibernate irá deletar todos os objetos do tipo Employee de seu cache.

Mas o NativeQuery funciona ainda mais interessante:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4")
nativeQuery.executeUpdate();

Uma consulta SQL nativa ao banco de dados foi executada. Isso significa que algo mudou no banco de dados - a solicitação foi chamada no método executeUpdate() . Portanto, neste caso, o Hibernate jogará pelo seguro e removerá todos os objetos de todos os tipos de seu cache .

Como você gosta disso? Você chama uma solicitação inofensiva e o Hibernate em resposta apaga todos os dados do cache! Isso certamente é melhor do que se ele mantivesse objetos diferentes da base, mas é isso!

Portanto, os criadores do Hibernate descobriram rapidamente como ajudar o Hibernate nesse caso. Você pode dizer qual tipo de entidade remover do cache:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
Observação . As consultas de seleção nativa não liberam o cache , apenas inserem, atualizam, excluem, chamadas de procedimento, etc.

Limpeza manual de cache

Por alguns motivos, você mesmo pode querer excluir um objeto do cache. Isso pode ser feito de diferentes maneiras.

Nota . Os objetos no cache são armazenados em grupos chamados regiões . Por padrão, o nome da região é igual ao nome da classe. Portanto, se você tiver objetos do tipo com.codegym.Employee , todos eles serão armazenados em um grupo (região) com o nome “ com.codegym.employee ”.

Se você deseja acessar o cache e fazer algo com ele, pode fazê-lo com o objeto SessionFactory e o método getCache() :

session.getSessionFactory().getCache().evictQueryRegion("com.codegym.employee”);

Se você deseja excluir dados de todos os grupos (regiões), é necessário executar a seguinte consulta:

session.getSessionFactory().getCache().evictAllRegions();

Para remover um objeto do cache, você precisa passar seu nome (tipo) e id. Você pode fazer isso de duas maneiras:

session.getSessionFactory().getCache().evictEntityData("Employee, 4);

session.getSessionFactory().getCache().evictEntityData(com.codegym.Employee.class, 4);

Você também pode verificar se um determinado objeto está no cache:

session.getSessionFactory().getCache().containsEntity("Employee, 4);
session.getSessionFactory().getCache().containsEntity(com.codegym.Employee.class, 4);