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).
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);
}
}
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
hibernate et JPA fournissent tous deux un accès direct au cache sous-jacent de 2e niveau:
sessionFactory.getCache().evict(..);
entityManager.getCache().evict(..)
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.
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.