2009-10-21 6 views
22

Wir haben eine Anwendung, die Hibernate's 2nd Level Caching verwendet, um Datenbanktreffer zu vermeiden.Hibernate 2nd level Cache Ungültigkeit, wenn ein anderer Prozess die Datenbank ändert

Ich frage mich, ob es einen einfachen Weg gibt, den Hibernate-2nd-Level-Cache der Java-Anwendung ungültig zu machen, wenn ein externer Prozess wie ein MySQL-Administrator direkt verbunden, um die Datenbank zu ändern (Update/Einfügen/Löschen).

Wir verwenden EHCache als unsere 2nd Level Cache-Implementierung.

Wir verwenden eine Mischung aus @Cache (usage = CacheConcurrencyStrategy.READ_WRITE) und @Cache (usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE), und wir haben kein Optimistic Concurrency Control aktiviert, das Timestamps für jede Entität verwendet.

Die Session enthält Methoden, um den zweiten Level-Cache zu verwalten: - Managing the 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 

Aber weil wir individuelle Entitätsklassen mit @Cache mit Anmerkungen versehen, gibt es keinen zentralen Platz für uns „zuverlässig“ (zB kein Handbuch Schritte) fügen Sie das zur Liste hinzu.

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

Es gibt keinen wirklichen Weg für 2nd Level Cache des Hibernate zu wissen, dass ein Unternehmen in der DB geändert, es sei denn, dass Entitätsabfragen (was der Cache Sie schützt). Also könnten wir als Lösung vielleicht eine Methode aufrufen, um den Second-Level-Cache zu zwingen, alles zu entfernen (wieder wegen mangelnder Sperr- und Nebenläufigkeitskontrolle riskieren Sie, dass Transaktionen vom "Lesen" oder Aktualisieren veralteter Daten ablaufen).

Antwort

14

Basierend auf ChssPly76's Kommentare hier ist eine Methode, die alle Einheiten vom 2.-Level-Cache evicts (können wir diese Methode, um Administratoren über JMX oder anderen Admin aussetzen Werkzeuge):

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

Ich möchte Cache-Daten aus 2nd-Level-Cache durch Aufruf von unten Methode löschen: - sessionFactory.getCache(). EvictEntityRegions(); Ich möchte nur wissen, gibt es einen Schaden dabei? Zum Beispiel: - Was passiert, wenn ich versuche, den Cache mitten in der Transaktion zu löschen? –

11

SessionFactory viel evict() Methoden hat genau zu diesem Zweck:

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

Gibt es eine zuverlässige Möglichkeit, alle Instanzen aller mit @Cache annotierten Klassen aus dem Cache der zweiten Ebene zu entfernen. Im Allgemeinen kommentieren wir die Klassen, um den Cache der zweiten Ebene zu aktivieren, und daher gibt es nicht wirklich eine zentrale Stelle zum Aktualisieren des Codes, wenn eine neue Entität zum Cache der zweiten Ebene hinzugefügt wird. – Dougnukem

+1

Um ehrlich zu sein, scheint die Vertreibung ** aller ** Fälle eher ein Extremfall zu sein. Tun Sie es oft genug und Sie können mit Leistung schlechter als mit überhaupt keinem Cache enden. Das heißt, Sie können Namen aller Entitäten über 'getAllClassMetadata()' Methode (Namen sind Schlüssel der zurückgegebenen Karte) und Aufruf 'evictEntity()' für jeden. – ChssPly76

+0

Dies ist nur eine äußerst seltene Gelegenheit, wenn wir eine Produktion "HOTFIX" der Datenbank durchführen müssen, ohne die Server herunterzufahren, und unsere vorhandenen Kundenservice-Admin-Tools können dies nicht tun (und wir würden lieber keinen Admin-Befehl veröffentlichen, der lässt Sie etwas beliebiges SQL ausführen). Durch das Zulassen, dass ein externer Administrator SQL ausführen kann, verlieren wir alle Transaktionsprüfungen und -protokollierungen. – Dougnukem

8

Sowohl hibernate und JPA nun direkten Zugriff auf die darunter liegende zweite Level-Cache bieten:

2

Ich war auf der Suche, wie man alle Hibernate Caches ungültig zu machen, und ich fand diese nützliche Schnipsel:

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

Hoffe, dass es jemand anderes hilft.

1

können Sie versuchen, dies zu tun:

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

Ich hoffe, es hilft.

Verwandte Themen