Frage

Ich muss oft implementieren DAOs für einige Referenzdaten, die nicht sehr oft ändern. I-Cache manchmal in Sammlung Feld auf der DAO - so dass es nur einmal geladen wird und explizit aktualisiert, wenn erforderlich.

Allerdings bringt dies in vielen Parallelitätsprobleme - was ist, wenn ein anderer Thread auf die Daten zuzugreifen versucht, während sie aktualisiert wird geladen oder wird.

aber für eine große Web-Anwendung ist dies durchaus ein Overhead

-

Natürlich kann dies, indem sie sowohl die Getter und Setter der Daten synchronisiert behandelt werden.

Ich habe ein triviales fehlerhaft Beispiel enthalten, was ich als strawman benötigen. Bitte legen nahe, alternative Möglichkeiten, um dies zu realisieren.

public class LocationDAOImpl implements LocationDAO {

private List<Location> locations = null;

public List<Location> getAllLocations() {
    if(locations == null) {
        loadAllLocations();
    }
    return locations;
}

Für weitere Informationen Ich verwende Hibernate und Spring, aber diese Anforderung für viele Technologien gelten würde.

Einige weitere Gedanken:

Sollte dies nicht in Code behandelt werden - stattdessen lassen ehcache oder ähnliche handelt es? Gibt es ein gemeinsames Muster für dieses, das ich fehlt? Es gibt natürlich viele Möglichkeiten, dies erreicht werden kann, aber ich habe nie ein Muster, das einfach und wartbar ist.

Vielen Dank im Voraus!

War es hilfreich?

Lösung

Wenn Sie nur eine schnelle Roll-Ihre eigene Caching-Lösung wollen, müssen Sie einen Blick auf this Artikel über JavaSpecialist, die eine Überprüfung des Buches ist, Brian Goetz .

Er spricht über eine grundlegende Threadsicherheit Cache Implementierung ein FutureTask und ein ConcurrentHashMap .

Die Art und Weise dies geschehen ist sichergestellt, dass nur ein Thread gleichzeitig löst die lange Laufberechnung (in Ihrem Fall Ihre Datenbank in DAO nennt).

Sie müssten diese Lösung modifizieren Cache Ablauf hinzufügen, wenn Sie es brauchen.

Der andere Gedanken über es selbst Cachen ist Garbage Collection. Ohne einen WeakHashMap für den Cache verwendet wird, dann würde die GC nicht in der Lage sein, den Speicher durch den Cache verwendet, um freizugeben, wenn nötig. Wenn Sie selten zugegriffen Daten zwischenspeichern (aber Daten, die noch im Wert von Caching waren, da es schwer zu berechnen ist), dann sollten Sie den Garbage Collector, um zu helfen, wenn durch die Verwendung eines WeakHashMap wenig Speicher ausgeführt wird.

Andere Tipps

Die einfache und sichere Art und Weise ist die ehcache Bibliothek in Ihrem Projekt enthält und dass die Einrichtung verwenden ein Cache. Diese Leute haben alle Probleme gelöst auftreten können, und sie haben die Bibliothek so schnell wie möglich gemacht.

In Situationen, in denen ich meine eigene Referenzdatencache gerollt habe, habe ich die Regel einen ReadWriteLock Thread-Konkurrenz zu reduzieren. Jeder meiner Accessoren nimmt dann die Form:

public PersistedUser getUser(String userName) throws MissingReferenceDataException {
    PersistedUser ret;

    rwLock.readLock().lock();
    try {
        ret = usersByName.get(userName);

        if (ret == null) {
            throw new MissingReferenceDataException(String.format("Invalid user name: %s.", userName));
        }
    } finally {
        rwLock.readLock().unlock();
    }

    return ret;
}

Die einzige Methode, die Schreibsperre zu nehmen ist refresh(), die ich über einen MBean typischerweise aussetzen:

public void refresh() {
    logger.info("Refreshing reference data.");
    rwLock.writeLock().lock();
    try {
        usersById.clear();
        usersByName.clear();

        // Refresh data from underlying data source.

    } finally {
        rwLock.writeLock().unlock();
    }
}

Im übrigen entschied ich mich für meine eigene Cache Implementierung, weil:

  • Meine Referenzdatensammlungen sind klein, so kann ich sie immer speichern alle im Speicher.
  • Meine app muss einfach / schnell sein; Ich mag so wenige Abhängigkeiten von externen Bibliotheken wie möglich.
  • Die Daten selten aktualisiert wird, und wenn es der Anruf () ist ziemlich schnell zu aktualisieren ist. Daher eifrig initialisiere ich meine Caches (anders als in Ihrem Strohmann Beispiel), was bedeutet, Accessoren nie die Schreibsperre nehmen müssen.

Wenn Sie Ihre Referenzdaten sind unveränderlich das Second Level Cache von Hibernate könnte eine vernünftige Lösung sein.

  

Natürlich kann dies sowohl, indem die Getter und Setter der Daten synchronisiert behandelt werden - aber für eine große Web-Anwendung ist dies durchaus ein Overhead.

     

Ich habe ein triviales fehlerhaft Beispiel enthalten, was ich als strawman benötigen. Bitte legen nahe, alternative Wege, dies zu implementieren.

Dies ist zwar etwas wahr sein könnte, sollten Sie zur Kenntnis nehmen, dass der Beispielcode Sie sicher synchronisiert werden muss zur Verfügung gestellt haben keine Parallelitätsprobleme zu vermeiden, wenn die locations faul-Laden. Wenn das Accessor nicht synchronisiert ist, dann haben Sie:

  • Mehr Threads greifen Sie auf die loadAllLocations() Methode zur gleichen Zeit
  • können einige Threads eingeben loadAllLocations() auch nach einem anderen Thread der Methode und das Ergebnis an locations zugewiesen abgeschlossen hat -. Unter dem Java-Speichermodell gibt es keine Garantie, dass andere Threads die Änderung in den Variablen ohne Synchronisation sehen

Seien Sie vorsichtig, wenn ein träges Laden / Initialisierung verwendet wird, es scheint wie eine einfache Leistungssteigerung, aber es kann viele unangenehme Threadingprobleme führen.

Ich denke, es ist am besten, es nicht selbst tun, weil es richtig hinzubekommen eine sehr schwierige Sache ist. Mit ehcache oder OSCache mit Hibernate und Spring ist eine weit bessere Idee.

Außerdem macht es Ihre DAOs Stateful, was problematisch sein könnte. Sie sollten überhaupt keinen Staat haben, neben den Anschluss, mit einer Fabrik oder einer Vorlage Objekte, die Feder für Sie verwaltet.

UPDATE: Wenn die Referenzdaten nicht zu groß ist, und wirklich ändert sich nie, vielleicht eine alternative Gestaltung wäre Aufzählungen zu erstellen und zusammen mit der Datenbank verzichtet werden kann. Kein Cache, kein Hibernate, keine Sorgen. Vielleicht oxbow_lakes' Punkt ist eine Überlegung wert. Vielleicht könnte es ein sehr einfaches System sein

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top