Hibernate 2ème niveau d'invalidation du cache lorsqu'un autre processus modifie la base de données

nous avons une application qui utilise la mise en cache de niveau 2 de Hibernate pour éviter les accès à la base de données.

je me demandais s'il y avait un moyen facile d'invalider le cache de niveau 2 de L'application Java lors d'un processus extérieur tel qu'un administrateur MySQL directement connecté pour modifier la base de données (update/insert/delete).

nous utilisons EHCache comme notre implémentation de cache de deuxième niveau.

<!-Nous utilisons un mélange de @Cache (usage = Cacheconcurrencestratégie.READ_WRITE) et @Cache(usage = Cacheconcurrencestrategy.NONSTRICT_READ_WRITE), et nous n'avons pas de contrôle de concurrence optimiste activé en utilisant des horodateurs sur chaque entité.

le répertoire SessionFactory contient des méthodes pour gérer le cache de deuxième niveau: - Gérer les 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

mais parce que nous annotons des classes d'entités individuelles avec @Cache, il n'y a pas de place centrale pour nous pour "fiable" (par exemple pas d'étapes manuelles) ajouter cela à la liste.

// 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);
   }
}

il n'y a pas de vrai moyen pour le cache de niveau 2 D'Hibernate de savoir qu'une entité a changé dans la base de données à moins qu'elle ne l'interroge (ce dont le cache vous protège). Donc peut-être que comme solution nous pourrions simplement appeler une méthode pour forcer le cache de deuxième niveau à tout expulser (encore une fois à cause du manque de verrouillage et de contrôle de la concurrence, vous risquez dans les transactions en cours de "lecture" ou de mise à jour des données périmées).

22
demandé sur Dougnukem 2009-10-22 01:45:23

5 réponses

basé sur Chssply76's commentaires voici une méthode qui expulse toutes les entities du cache de deuxième niveau (nous pouvons exposer cette méthode aux administrateurs via JMX ou d'autres outils d'administration):

/**
 * 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);
    }
}
14
répondu Dougnukem 2017-05-23 11:46:42

SessionFactory a beaucoup de evict() méthodes précisément dans ce but:

sessionFactory.evict(MyEntity.class); // remove all MyEntity instances
sessionFactory.evict(MyEntity.class, new Long(1)); // remove a particular MyEntity instances
11
répondu ChssPly76 2009-10-21 22:00:23

hibernate et JPA fournissent tous deux un accès direct au cache sous-jacent de 2e niveau:

sessionFactory.getCache().evict(..);
entityManager.getCache().evict(..)
8
répondu Bozho 2012-05-15 09:01:23

je cherchais comment invalider toutes les caches D'hibernation et j'ai trouvé cet extrait utile:

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

J'espère que ça aidera quelqu'un d'autre.

2
répondu jelies 2014-03-11 10:03:08

Vous pouvez essayer de faire ceci:

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;
}

j'espère que Cela aide.

1
répondu Aalkhodiry 2014-05-28 09:02:31