Ich neige dazu, Hibernate in Kombination mit dem Spring- Framework und seinen deklarativen Transaktionsabgrenzungsfunktionen (z . B. @Transactional ) zu verwenden.
Wie wir alle wissen, versucht der Winterschlaf, so wenig invasiv und transparent wie möglich zu sein. Dies ist jedoch bei der Verwendung von Beziehungen etwas schwierigerlazy-loaded
.
Ich sehe eine Reihe von Designalternativen mit unterschiedlichen Transparenzstufen.
- Machen Sie Beziehungen nicht faul geladen (z.
fetchType=FetchType.EAGER)
- Dies vioalites die gesamte Idee des faulen Ladens ..
- Initialisieren Sie Sammlungen mit
Hibernate.initialize(proxyObj);
- Dies impliziert eine relativ hohe Kopplung an das DAO
- Obwohl wir eine Schnittstelle mit definieren können
initialize
, wird nicht garantiert, dass andere Implementierungen eine Entsprechung bieten.
- Fügen Sie den persistenten
Model
Objekten selbst Transaktionsverhalten hinzu (entweder mit dynamischem Proxy oder@Transactional
)- Ich habe den dynamischen Proxy-Ansatz nicht ausprobiert, obwohl ich @Transactional anscheinend nie dazu gebracht habe, an den persistenten Objekten selbst zu arbeiten. Wahrscheinlich aufgrund dieses Ruhezustands ist die Operation auf einem Proxy zu sein.
- Kontrollverlust, wenn Transaktionen tatsächlich stattfinden
- Stellen Sie sowohl die Lazy / Non-Lazy-API bereit, z. B.
loadData()
undloadDataWithDeps()
- Erzwingt, dass die Anwendung weiß, wann welche Routine anzuwenden ist, wieder eine enge Kopplung
- Methodenüberlauf ,,
loadDataWithA()
....,loadDataWithX()
- Erzwingen Sie die Suche nach Abhängigkeiten, z. B. indem Sie nur
byId()
Operationen bereitstellen- Benötigt eine Menge nicht objektorientierter Routinen, z. B.
findZzzById(zid)
und danngetYyyIds(zid)
anstelle vonz.getY()
- Es kann nützlich sein, jedes Objekt in einer Sammlung einzeln abzurufen, wenn zwischen den Transaktionen ein großer Verarbeitungsaufwand besteht.
- Benötigt eine Menge nicht objektorientierter Routinen, z. B.
- Machen Sie einen Teil der Anwendung @Transactional anstelle nur des DAO
- Mögliche Überlegungen zu verschachtelten Transaktionen
- Erfordert Routinen, die für das Transaktionsmanagement angepasst sind (z. B. ausreichend klein)
- Kleine programmatische Auswirkungen, obwohl dies zu großen Transaktionen führen kann
- Stellen Sie dem DAO dynamische Abrufprofile zur Verfügung , z.
loadData(id, fetchProfile);
- Anwendungen müssen wissen, welches Profil wann verwendet werden soll
- Transaktionen vom Typ AoP, z. B. Abfangen von Operationen und Ausführen von Transaktionen, falls erforderlich
- Erfordert die Manipulation von Bytecode oder die Verwendung von Proxys
- Kontrollverlust bei Transaktionen
- Schwarze Magie wie immer :)
Habe ich eine Option verpasst?
Welches ist Ihr bevorzugter Ansatz, wenn Sie versuchen, die Auswirkungen von lazy-loaded
Beziehungen in Ihrem Anwendungsdesign zu minimieren ?
(Oh, und Entschuldigung für WoT )
java
hibernate
spring
lazy-loading
application-design
Johan Sjöberg
quelle
quelle
Antworten:
Ich würde sagen, die ursprüngliche Annahme ist falsch. Transaparente Persistenz ist ein Mythos, da die Anwendung immer den Entitätslebenszyklus und die Größe des geladenen Objektgraphen berücksichtigen sollte.
Beachten Sie, dass der Ruhezustand keine Gedanken lesen kann. Wenn Sie also wissen, dass Sie bestimmte Abhängigkeiten für einen bestimmten Vorgang benötigen, müssen Sie Ihre Absichten für den Ruhezustand irgendwie zum Ausdruck bringen.
Unter diesem Gesichtspunkt sehen Lösungen, die diese Absichten explizit ausdrücken (nämlich 2, 4 und 7), vernünftig aus und leiden nicht unter dem Mangel an Transparenz.
quelle
Ich bin nicht sicher, auf welches Problem (verursacht durch Faulheit) Sie hinweisen, aber für mich besteht der größte Schmerz darin, den Sitzungskontext in meinen eigenen Anwendungscaches nicht zu verlieren. Typischer Fall:
foo
wird geladen und in eine Karte eingefügt;foo.getBar()
(etwas, das noch nie aufgerufen wurde und faul ausgewertet wird).Um dies anzugehen, haben wir eine Reihe von Regeln:
OpenSessionInViewFilter
für Webapps);try/finally
), sodass Unterklassen nicht darüber nachdenken müssen;Wie Sie sehen, ist dies in der Tat nicht annähernd nicht invasiv und transparent . Aber die Kosten sind immer noch erträglich, verglichen mit dem Preis, den ich für eifriges Laden zahlen müsste. Das Problem bei letzterem ist, dass es manchmal zum Schmetterlingseffekt führt, wenn ein einzelnes referenziertes Objekt geladen wird, geschweige denn eine Sammlung von Entitäten. Der Speicherverbrauch, die CPU-Auslastung und die Latenz, um es gelinde auszudrücken, sind ebenfalls weitaus schlechter, sodass ich damit leben kann.
quelle
transparency
besteht darin, dass die Anwendung gezwungen wird, sich um das Laden fauler Objekte zu kümmern. Wenn alles geholt wurde eifrig die Anwendung konnte vollständig nicht bewusst sein , ob die Objekte in einer Datenbank beibehalten werden oder nicht, daFoo.getBar()
immer erfolgreich. >when passing objects between threads, pass IDs
ja, das würde # 5 entsprechen.Ein sehr häufiges Muster ist die Verwendung von OpenEntityManagerInViewFilter, wenn Sie eine Webanwendung erstellen.
Wenn Sie einen Dienst erstellen, würde ich den TX für die öffentliche Methode des Dienstes und nicht für die DAOs öffnen, da eine Methode sehr oft das Abrufen oder Aktualisieren mehrerer Entitäten erfordert.
Dadurch wird jede "Lazy Load-Ausnahme" gelöst. Wenn Sie für die Leistungsoptimierung etwas Fortgeschritteneres benötigen, ist das Abrufen von Profilen meiner Meinung nach der richtige Weg.
quelle
OSIV
ist immer noch ein Antimuster und führt zu sehr schwerwiegenden Problemen wie der Unfähigkeit, Ausnahmen oder Leistungseinbußen ordnungsgemäß zu behandeln. Zusammenfassend: IMHO OSIV ist eine unkomplizierte Lösung, aber nur für Spielzeugprojekte geeignet.