Hibernate: différence entre session.get et session.load

88

À partir de l'API, je pouvais voir que cela avait quelque chose à voir avec le proxy. Mais je n'ai pas trouvé beaucoup d'informations sur le proxy et je ne comprends pas la différence entre appeler session.getet session.load. Quelqu'un pourrait-il s'il vous plaît m'expliquer ou me diriger vers une page de référence?

Je vous remercie!!

tomate
la source

Réponses:

117

Depuis le forum Hibernate :

Ceci du livre Hibernate in Action. Bonne lecture.


Récupération d'objets par identifiant L'extrait de code Hibernate suivant récupère un objet User de la base de données:

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

La méthode get () est spéciale car l'identifiant identifie de manière unique une seule instance d'une classe. Par conséquent, il est courant pour les applications d'utiliser l'identifiant comme un descripteur pratique d'un objet persistant. La récupération par identificateur peut utiliser le cache lors de la récupération d'un objet, évitant un hit de base de données si l'objet est déjà mis en cache. Hibernate fournit également une méthode load ():

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

La méthode load () est plus ancienne; get () a été ajouté à l'API d'Hibernate en raison de la demande de l'utilisateur. La différence est triviale:

Si load () ne trouve pas l'objet dans le cache ou la base de données, une exception est levée. La méthode load () ne renvoie jamais null. La méthode get () retourne null si l'objet est introuvable.

La méthode load () peut renvoyer un proxy au lieu d'une véritable instance persistante. Un proxy est un espace réservé qui déclenche le chargement de l'objet réel lorsqu'il y accède pour la première fois; D'un autre côté, get () ne renvoie jamais de proxy. Le choix entre get () et load () est facile: si vous êtes certain que l'objet persistant existe et que la non-existence serait considérée comme exceptionnelle, load () est une bonne option. Si vous n'êtes pas certain qu'il existe une instance persistante avec l'identifiant donné, utilisez get () et testez la valeur de retour pour voir si elle est nulle. L'utilisation de load () a une autre implication: l'application peut récupérer une référence valide (un proxy) vers une instance persistante sans toucher la base de données pour récupérer son état persistant. Ainsi load () peut ne pas lancer d'exception lorsqu'il ne trouve pas l'objet persistant dans le cache ou la base de données; l'exception serait levée plus tard, lors de l'accès au proxy. Bien sûr, la récupération d'un objet par identifiant n'est pas aussi flexible que l'utilisation de requêtes arbitraires.

duffymo
la source
1
Je débogue actuellement un problème où session.Get <T> () renvoie un proxy!
Kent Boogaart
7
Merci beaucoup! La partie argent pour moi était: "Si load () ne peut pas trouver l'objet dans le cache ou la base de données, une exception est levée. La méthode get () renvoie null si l'objet est introuvable."
Chris
15
Le JavaDoc pour Session.get dit: Renvoie l'instance persistante de la classe d'entité donnée avec l'identifiant donné, ou null s'il n'y a pas d'instance persistante. (Si l'instance, ou un proxy pour l'instance, est déjà associé à la session, renvoyez cette instance ou ce proxy.) Donc, la section du livre qui dit: "D'un autre côté, get () ne renvoie jamais de proxy." n'est pas correcte.
Vicky
si vous utilisez une stratégie de gestion des transactions avec vos daos, vous préférerez peut-être get (). sinon l'appelant devra également être en cours d'exécution dans le contexte d'une session de mise en veille prolongée ouverte au cas où load () retourne un proxy. par exemple, si vous faites MVC, votre contrôleur peut exécuter dao.load () puis lancer une exception lors d'une tentative d'accès à l'objet proxy ultérieurement s'il n'y a pas de session valide. faire dao.get () retournera l'objet réel au contrôleur quelle que soit la session (en supposant qu'il existe)
dev
Le problème décrit par @Vicky peut causer des maux de tête, et je n'en vois aucun avantage. Dans certains cas, j'ai également besoin de l'identifiant pour d'autres requêtes paramétrées. Mais comme un proxy de l'objet est déjà dans la session, le getter de l'identifiant renvoie null. Pourquoi récupèrent-ils le proxy plutôt que l'instance réelle si ce proxy est dans la session?
djmj
15

Eh bien, dans nhibernate au moins, session.Get (id) chargera l'objet à partir de la base de données, tandis que session.Load (id) ne lui créera qu'un objet proxy sans quitter votre serveur. Fonctionne comme toutes les autres propriétés chargées paresseusement dans vos POCO (ou POJO :). Vous pouvez ensuite utiliser ce proxy comme référence à l'objet lui-même pour créer des relations, etc.

Pensez-y comme si vous aviez un objet qui ne garde que l'identifiant et qui chargera le reste si jamais vous en avez besoin. Si vous le transmettez simplement pour créer des relations (comme des FK), l'id est tout ce dont vous aurez besoin.

Jorge Alves
la source
vous voulez donc dire que load (id) frappera d'abord la base de données pour vérifier s'il s'agit d'un id valide ou non et que retournera l'objet proxy et que lorsque les propriétés de cet objet seront accédées, il atteindra à nouveau la base de données? n'est-ce pas un scénario improbable? deux requêtes pour charger un seul objet?
faisalbhagat
Non, load (id) ne validera pas du tout l'id donc pas d'aller-retour vers la base de données. Utilisez-le uniquement lorsque vous êtes sûr de sa validité.
Jorge Alves
9

session.load () retournera toujours un «proxy» (terme Hibernate) sans toucher la base de données. Dans Hibernate, le proxy est un objet avec la valeur d'identifiant donnée, ses propriétés ne sont pas encore initialisées, il ressemble juste à un faux objet temporaire. Si aucune ligne n'est trouvée, il lèvera une ObjectNotFoundException.

session.get () frappe toujours la base de données et renvoie l'objet réel, un objet qui représente la ligne de la base de données, pas le proxy. Si aucune ligne n'est trouvée, elle renvoie null.

Les performances avec ces méthodes font également des différences. entre deux...

Vishal Sharma
la source
3

Encore un point supplémentaire:

La méthode get de la classe Hibernate Session renvoie null si l'objet n'est pas trouvé dans le cache ainsi que sur la base de données. tandis que la méthode load () lève ObjectNotFoundException si l'objet n'est pas trouvé sur le cache ainsi que sur la base de données mais ne retourne jamais null.

madhu_karnati
la source
2

Une conséquence indirecte de l'utilisation de "load" au lieu de "get" est que le verrouillage optimiste utilisant un attribut de version peut ne pas fonctionner comme prévu. Si une charge crée simplement un proxy et ne lit pas à partir de la base de données, la propriété version n'est pas chargée. La version ne sera chargée que lorsque / si vous vous référez plus tard à une propriété de l'objet, déclenchant une sélection. En attendant, une autre session peut mettre à jour l'objet et votre session n'aura pas la version d'origine dont elle a besoin pour effectuer la vérification de verrouillage optimiste - la mise à jour de votre session écrasera la mise à jour de l'autre session sans avertissement.

Voici une tentative d'esquisser ce scénario avec deux sessions travaillant avec un objet avec le même identifiant. La version initiale de l'objet dans DB est 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]

Nous voulons en fait que la validation de la session 1 échoue avec une exception de verrouillage optimiste, mais cela réussira ici.

L'utilisation de "get" au lieu de "load" permet de contourner le problème, car get émettra immédiatement une sélection, et les numéros de version seront chargés au bon moment pour la vérification optimiste du verrouillage.

SteveT
la source
0

Nous devons également faire attention lors de l'utilisation de load car il lèvera une exception si l'objet n'est pas présent. Nous ne devons l'utiliser que lorsque nous sommes sûrs que cet objet existe.

Sanjay
la source
0

Une excellente explication se trouve sur http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
il renverra toujours un «proxy» (terme Hibernate) sans frapper la base de données.
Dans Hibernate, le proxy est un objet avec la valeur d'identifiant donnée, ses propriétés ne sont pas encore initialisées, il ressemble juste à un faux objet temporaire.
Il renverra toujours un objet proxy avec la valeur d'identité donnée, même si la valeur d'identité n'existe pas dans la base de données. Cependant, lorsque vous essayez d'initialiser un proxy en récupérant ses propriétés de la base de données, il atteindra la base de données avec l'instruction select. Si aucune ligne n'est trouvée, une ObjectNotFoundException sera lancée.
session.get ():
Il frappe toujours la base de données (s'il n'est pas trouvé dans le cache) et renvoie l'objet réel, un objet qui représente la ligne de la base de données, pas le proxy.
Si aucune ligne n'est trouvée, elle renvoie null.

prise noire
la source
0

load () ne trouve pas l'objet à partir du cache ou de la base de données, une exception est levée et la méthode load () ne renvoie jamais null.

La méthode get () renvoie null si l'objet est introuvable. La méthode load () peut retourner un proxy au lieu d'une instance réelle persistante get () ne renvoie jamais de proxy.

Yasser Shaikh
la source