Pergunta

Temos um aplicativo que usa o cache de 2º nível do Hibernate para evitar acertos de banco de dados.

Fiquei me perguntando se existe uma maneira fácil de invalidar o cache do 2º nível de Hibernate do aplicativo Java quando um processo externo, como um administrador do MySQL, conectado diretamente para modificar o banco de dados (atualizar/inserir/delete).

Nós estamos usando Ehcache Como nossa implementação de cache de 2º nível.

Utilizamos uma mistura de @cache (usoge = cacheCoCurrencystrategy.read_write) e @cache (usage = cacheCoCurncyRencystrategy.nonstric_read_write) e não temos controle de concorrência otimista ativado usando timestamps em cada entidade.

O SessionFactory contém métodos para gerenciar o cache do 2º nível: - Gerenciando os caches

sessionFactory.evict(Cat.class, catId); //evict a particular Cat
sessionFactory.evict(Cat.class);  //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections

Mas como anotamos aulas de entidade individuais com o @cache, não há lugar central para "" confiabilidade "(por exemplo, etapas manuais) adicionam isso à lista.

// Easy to forget to update this to properly evict the class
public static final Class[] cachedEntityClasses = {Cat.class, Dog.class, Monkey.class}

public void clear2ndLevelCache() {
  SessionFactory sessionFactory = ...   //Retrieve SessionFactory

   for (Class entityClass : cachedEntityClasses) {
       sessionFactory.evict(entityClass);
   }
}

Não existe uma maneira real de saber que uma entidade mudou no banco de dados, a menos que consulte essa entidade (que é do que o cache está protegendo você). Então, talvez como uma solução, poderíamos simplesmente chamar algum método para forçar o cache de segundo nível a despejar tudo (novamente devido à falta de controle de bloqueio e simultaneidade, você corre o risco de transações de progresso da "leitura" ou da atualização de dados obsoletos).

Foi útil?

Solução

Baseado em CHSSPLY76's Comentários Aqui está um método que despeja todas as entidades do cache do 2º nível (podemos expor esse método a administradores por meio de JMX ou outras ferramentas de administrador):

/**
 * Evicts all second level cache hibernate entites. This is generally only
 * needed when an external application modifies the game databaase.
 */
public void evict2ndLevelCache() {
    try {
        Map<String, ClassMetadata> classesMetadata = sessionFactory.getAllClassMetadata();
        for (String entityName : classesMetadata.keySet()) {
            logger.info("Evicting Entity from 2nd level cache: " + entityName);
            sessionFactory.evictEntity(entityName);
        }
    } catch (Exception e) {
        logger.logp(Level.SEVERE, "SessionController", "evict2ndLevelCache", "Error evicting 2nd level hibernate cache entities: ", e);
    }
}

Outras dicas

SessionFactory tem muito evict() Métodos precisamente para esse fim:

sessionFactory.evict(MyEntity.class); // remove all MyEntity instances
sessionFactory.evict(MyEntity.class, new Long(1)); // remove a particular MyEntity instances

Hibernate e JPA agora fornecem acesso direto ao cache do 2º nível subjacente:

sessionFactory.getCache().evict(..);
entityManager.getCache().evict(..)

Eu estava pesquisando como invalidar todos os caches de hibernação e achei este trecho útil:

sessionFactory.getCache().evictQueryRegions();
sessionFactory.getCache().evictDefaultQueryRegion();
sessionFactory.getCache().evictCollectionRegions();
sessionFactory.getCache().evictEntityRegions();

Espero que ajude para outra pessoa.

Você pode tentar fazer isso:

private EntityManager em;

public void clear2ndLevelHibernateCache() {
    Session s = (Session) em.getDelegate();
    SessionFactory sf = s.getSessionFactory();

    sf.getCache().evictQueryRegions();
    sf.getCache().evictDefaultQueryRegion();
    sf.getCache().evictCollectionRegions();
    sf.getCache().evictEntityRegions();

    return;
}

Espero que ajude.

Uma coisa a levar em consideração ao usar o cache distribuído é que o Querycache é local e evitá -lo em um nó, não o despeja de outros. Outra questão é: a região da entidade sem despejar a região de consulta causará N+1 seleciona, ao tentar recuperar a data do cache de consulta. Boas leituras sobre este tópico aqui.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top