Ruhezustand: Unterschied zwischen session.get und session.load

88

An der API konnte ich erkennen, dass sie etwas mit Proxy zu tun hat. Aber ich konnte nicht viele Informationen über Proxy finden und verstehe den Unterschied zwischen Anrufen session.getund nicht session.load. Könnte mich bitte jemand erklären oder auf eine Referenzseite verweisen?

Danke dir!!

Tomate
quelle

Antworten:

117

Aus dem Hibernate-Forum :

Dies aus dem Buch Hibernate in Action. Gut, dass man das gelesen hat ..


Abrufen von Objekten nach Kennung Mit dem folgenden Code-Snippet im Ruhezustand wird ein Benutzerobjekt aus der Datenbank abgerufen:

User user = (User) session.get(User.class, userID);

Die Methode get () ist etwas Besonderes, da der Bezeichner eine einzelne Instanz einer Klasse eindeutig identifiziert. Daher verwenden Anwendungen den Bezeichner häufig als praktisches Handle für ein beständiges Objekt. Das Abrufen nach Kennung kann den Cache beim Abrufen eines Objekts verwenden und einen Datenbanktreffer vermeiden, wenn das Objekt bereits zwischengespeichert ist. Hibernate bietet auch eine load () -Methode:

User user = (User) session.load(User.class, userID);

Die load () -Methode ist älter; get () wurde aufgrund einer Benutzeranforderung zur Hibernate-API hinzugefügt. Der Unterschied ist trivial:

Wenn load () das Objekt nicht im Cache oder in der Datenbank finden kann, wird eine Ausnahme ausgelöst. Die load () -Methode gibt niemals null zurück. Die Methode get () gibt null zurück, wenn das Objekt nicht gefunden werden kann.

Die load () -Methode gibt möglicherweise einen Proxy anstelle einer echten persistenten Instanz zurück. Ein Proxy ist ein Platzhalter, der beim erstmaligen Zugriff das Laden des realen Objekts auslöst. Andererseits gibt get () niemals einen Proxy zurück. Die Wahl zwischen get () und load () ist einfach: Wenn Sie sicher sind, dass das persistente Objekt vorhanden ist und keine Existenz als außergewöhnlich angesehen wird, ist load () eine gute Option. Wenn Sie nicht sicher sind, ob es eine persistente Instanz mit dem angegebenen Bezeichner gibt, verwenden Sie get () und testen Sie den Rückgabewert, um festzustellen, ob er null ist. Die Verwendung von load () hat eine weitere Auswirkung: Die Anwendung kann einen gültigen Verweis (einen Proxy) auf eine persistente Instanz abrufen, ohne die Datenbank zu treffen, um ihren persistenten Status abzurufen. Load () löst daher möglicherweise keine Ausnahme aus, wenn das persistente Objekt nicht im Cache oder in der Datenbank gefunden wird. Die Ausnahme wird später ausgelöst, wenn auf den Proxy zugegriffen wird. Das Abrufen eines Objekts anhand eines Bezeichners ist natürlich nicht so flexibel wie die Verwendung beliebiger Abfragen.

Duffymo
quelle
1
Ich debugge gerade ein Problem, bei dem session.Get <T> () einen Proxy zurückgibt!
Kent Boogaart
7
Vielen Dank! Der Geldteil für mich war: "Wenn load () das Objekt im Cache oder in der Datenbank nicht finden kann, wird eine Ausnahme ausgelöst. Die Methode get () gibt null zurück, wenn das Objekt nicht gefunden werden kann."
Chris
15
Das JavaDoc für Session.get lautet: Gibt die persistente Instanz der angegebenen Entitätsklasse mit dem angegebenen Bezeichner zurück oder null, wenn es keine solche persistente Instanz gibt. (Wenn die Instanz oder ein Proxy für die Instanz bereits mit der Sitzung verknüpft ist, geben Sie diese Instanz oder diesen Proxy zurück.) Der Abschnitt aus dem Buch, der besagt: "Auf der anderen Seite gibt get () niemals einen Proxy zurück." das ist nicht richtig.
Vicky
Wenn Sie mit Ihren Daos eine Transaktionsverwaltungsstrategie verwenden, bevorzugen Sie möglicherweise get (). Andernfalls muss der Aufrufer auch im Kontext einer offenen Ruhezustandssitzung ausgeführt werden, falls load () einen Proxy zurückgibt. Wenn Sie beispielsweise MVC ausführen, führt Ihr Controller möglicherweise dao.load () aus und löst dann eine Ausnahme aus, wenn Sie später versuchen, auf das Proxy-Objekt zuzugreifen, wenn keine gültige Sitzung vorhanden ist. Wenn Sie dao.get () ausführen, wird das tatsächliche Objekt unabhängig von der Sitzung an den Controller zurückgegeben (vorausgesetzt, es existiert)
dev
Das von @Vicky beschriebene Problem kann Kopfschmerzen verursachen, und ich sehe keinen Vorteil daraus. In einigen Fällen benötige ich zusätzlich die Kennung für weitere parametrisierte Abfragen. Da sich jedoch bereits ein Proxy des Objekts in der Sitzung befindet, gibt der Getter des Bezeichners null zurück. Warum rufen sie den Proxy anstelle der realen Instanz ab, wenn sich dieser Proxy in der Sitzung befindet?
DJMJ
15

Nun, zumindest in nhibernate lädt session.Get (id) das Objekt aus der Datenbank, während session.Load (id) nur ein Proxy-Objekt dafür erstellt, ohne Ihren Server zu verlassen. Funktioniert genau wie jede andere faul geladene Eigenschaft in Ihren POCOs (oder POJOs :). Sie können diesen Proxy dann als Referenz auf das Objekt selbst verwenden, um Beziehungen usw. zu erstellen.

Stellen Sie sich ein Objekt vor, das nur die ID behält und den Rest lädt, wenn Sie es jemals brauchen. Wenn Sie es nur weitergeben, um Beziehungen aufzubauen (wie FKs), ist die ID alles, was Sie jemals brauchen werden.

Jorge Alves
quelle
Sie möchten also sagen, dass load (id) zuerst die Datenbank trifft, um zu überprüfen, ob sie eine gültige ID hat oder nicht, und dann das Proxy-Objekt zurückgibt. Wenn auf die Eigenschaften dieses Objekts zugegriffen wird, trifft es erneut auf die Datenbank? Ist es nicht ein unwahrscheinliches Szenario? zwei Abfragen zum Laden eines einzelnen Objekts?
Faisalbhagat
Nein, load (id) validiert die ID überhaupt nicht, daher keine Roundtrips zur DB. Verwenden Sie es nur, wenn Sie sicher sind, dass es gültig ist.
Jorge Alves
9

session.load () gibt immer einen "Proxy" (Ruhezustand) zurück, ohne die Datenbank zu treffen. Im Ruhezustand ist Proxy ein Objekt mit dem angegebenen Bezeichnerwert. Seine Eigenschaften sind noch nicht initialisiert. Es sieht lediglich wie ein temporäres gefälschtes Objekt aus. Wenn keine Zeile gefunden wird, wird eine ObjectNotFoundException ausgelöst.

session.get () trifft immer auf die Datenbank und gibt das reale Objekt zurück, ein Objekt, das die Datenbankzeile darstellt, nicht den Proxy. Wenn keine Zeile gefunden wird, wird null zurückgegeben.

Die Leistung mit diesen Methoden macht auch Unterschiede. zwischen zwei...

Vishal Sharma
quelle
3

Noch ein Extrapunkt ::

Die Methode get der Klasse Hibernate Session gibt null zurück, wenn das Objekt nicht im Cache oder in der Datenbank gefunden wird. Die Methode load () löst eine ObjectNotFoundException aus, wenn das Objekt nicht sowohl im Cache als auch in der Datenbank gefunden wird, aber niemals null zurückgibt.

madhu_karnati
quelle
2

Eine indirekte Folge der Verwendung von "load" anstelle von "get" ist, dass das optimistische Sperren mit einem Versionsattribut möglicherweise nicht wie erwartet funktioniert. Wenn beim Laden einfach ein Proxy erstellt und nicht aus der Datenbank gelesen wird, wird die Versionseigenschaft nicht geladen. Die Version wird nur geladen, wenn Sie später auf eine Eigenschaft des Objekts verweisen und eine Auswahl auslösen. In der Zwischenzeit kann eine andere Sitzung das Objekt aktualisieren, und Ihre Sitzung verfügt nicht über die Originalversion, die für die optimistische Sperrprüfung erforderlich ist. Das Update Ihrer Sitzung überschreibt daher das Update der anderen Sitzung ohne Warnung.

Hier ist ein Versuch, dieses Szenario mit zwei Sitzungen zu skizzieren, die mit einem Objekt mit derselben Kennung arbeiten. Die ursprüngliche Version für das Objekt in der Datenbank ist 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

Wir möchten, dass das Commit von Sitzung 1 mit einer optimistischen Sperrausnahme fehlschlägt, aber hier wird es erfolgreich sein.

Die Verwendung von "get" anstelle von "load" umgeht das Problem, da get sofort eine Auswahl ausgibt und die Versionsnummern zum richtigen Zeitpunkt für die optimistische Sperrprüfung geladen werden.

SteveT
quelle
0

Außerdem müssen wir bei der Verwendung von load vorsichtig sein, da dies eine Ausnahme auslöst, wenn das Objekt nicht vorhanden ist. Wir müssen es nur verwenden, wenn wir sicher sind, dass das Objekt existiert.

Sanjay
quelle
0

Eine ausgezeichnete Erklärung finden Sie unter http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
Es wird immer ein "Proxy" (Ruhezustand) ohne zurückgegeben Schlagen Sie die Datenbank.
Im Ruhezustand ist Proxy ein Objekt mit dem angegebenen Bezeichnerwert. Seine Eigenschaften sind noch nicht initialisiert. Es sieht lediglich wie ein temporäres gefälschtes Objekt aus.
Es wird immer ein Proxy-Objekt mit dem angegebenen Identitätswert zurückgegeben, auch wenn der Identitätswert nicht in der Datenbank vorhanden ist. Wenn Sie jedoch versuchen, einen Proxy durch Abrufen seiner Eigenschaften aus der Datenbank zu initialisieren, wird er mit der select-Anweisung in die Datenbank aufgenommen. Wenn keine Zeile gefunden wird, wird eine ObjectNotFoundException ausgelöst.
session.get ():
Es trifft immer die Datenbank (wenn es nicht im Cache gefunden wird) und gibt das reale Objekt zurück, ein Objekt, das die Datenbankzeile darstellt, nicht den Proxy.
Wenn keine Zeile gefunden wird, wird null zurückgegeben.

schwarzer Wagenheber
quelle
0

load () kann das Objekt nicht aus dem Cache oder der Datenbank finden, es wird eine Ausnahme ausgelöst und die load () -Methode gibt niemals null zurück.

Die Methode get () gibt null zurück, wenn das Objekt nicht gefunden werden kann. Die load () -Methode gibt möglicherweise einen Proxy anstelle einer echten persistenten Instanz zurück. Get () gibt niemals einen Proxy zurück.

Yasser Shaikh
quelle