Hibernate : différence entre get() et load()

Si vous êtes un utilisateur d'Hibernate, que ce soit avec Spring ou pas, vous êtes vous déjà posé la question de savoir quelles sont les différences entre session.load() et session.get(). Comprendre les différences permet souvent d'optimiser les accès à la base de données.

En effet les signatures des deux méthodes sont assez proches et permettent toutes les deux de récupérer une entité via sa clé. Voici donc les différences :

  • get() renvoie null si l'objet n'existe pas, tandis que load() lève une objectNotFoundException. Ce qui veux dire que le fait que l'objet n'existe pas est considérer comme une erreur applicative. Il faut donc utiliser load() si tel est le cas. Par contre la javadoc est claire : You should not use this method to determine if an instance exists (use get() instead). en résumé n'en faites pas une utilisation détournée ;)
  • La deuxième différence est structurelle. Lorsque vous faites un get(), vous récupérez l'objet avec ses champs chargés (en fonction des attributs lazy, cela va sans dire). En revanche lorsque vous faites un load, Hibernate vous renvoie un proxy que sera initialisé lors de l'appel à un champs ou a un getter. Si la session est fermé, vous aurez alors une LazyInitializationException :
session.beginTransaction();

User user=(User) session.load(User.class, new Long(1));

session.getTransaction().commit();

user.getPassword();//=>LazyInitializationException

Vous n'auriez pas eu cette exception si vous auriez utilisé get()

La question qui vient alors à l'esprit est "si on ne doit pas utiliser load() pour tester l'existence d'un objet, et que les champs ne sont pas initialisés, quand utilisez load()?"

En fait, la réponse découle du modèle relationnel du SQL : lorsque vous avez une association OneToMany cela se traduit pas une relation de clé primaire / étrangère. Chose qui n'existe pas dans le modèle Objet (d'où l'intérêt d'Hibernate ;) ). pour associer un objet en SQL il suffit uniquement de connaitre la clé primaire de l'objet associé. et c'est là qu'intervient l'utilité de load(). Nous n'avons besoin que de sa clé, pas des champs. voici un exemple de code :

Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

User owner = session.get( User.class, 1 );//un appel
Car  car = session.get( Car.class, 2 );//deux appel
owner.setCar(car);//un save

tx.commit();
session.close();

Cela fait deux appels à la database + un save (pas de cache dans notre exemple). En revanche :


Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

User owner = session.load( User.class, 1 );
Car  car = session.get( Car.class, 2 );//un appel
owner.setCar(car);//un update

tx.commit();
session.close();

Nous avons économisé un appel à la base.

à vos refactoring :)

La discussion continue ailleurs

URL de rétrolien : https://davidmasclet.gisgraphy.com/index.php?trackback/27

Fil des commentaires de ce billet