🎬 Passer en mode présentation

Hibernate — Relations, Mapping et Fetch


1. Les relations entre deux tables

Règle de la spécification JPA (respectée par Hibernate) :

  • Les associations vers une seule entité (to-one) sont EAGER par défaut
  • Les collections (to-many) sont LAZY par défaut

Il faut éviter autant que possible les relations bidirectionnelles

Tableau des relations (annotations JPA / balises HBM)

Annotation JPA Balise HBM Cardinalité Fetch par défaut Peut être LAZY ?
@ManyToOne <many-to-one> N – 1 EAGER ✅ Oui — lazy="proxy" (défaut HBM)
@OneToOne (owning side) <one-to-one constrained="true"> 1 – 1 EAGER ✅ Oui — proxy possible car FK contrainte
@OneToOne (inverse mappedBy) <one-to-one constrained="false"> 1 – 1 EAGER Non — LAZY impossible par nature
@OneToMany <one-to-many> dans <set> 1 – N LAZY ✅ Déjà LAZY par défaut
@ManyToMany <many-to-many> dans <set> N – N LAZY ✅ Déjà LAZY par défaut

2. @OneToOne inverse

C'est la limitation structurelle la plus importante. Avec constrained="false" (ou mappedBy côté JPA), Hibernate ne sait pas a priori si la ligne associée existe en base. Pour créer un proxy, Hibernate est obligé d'émettre une requête immédiate pour le vérifier.

Hibernate :

"Note that if constrained="false", proxying is impossible and Hibernate will eagerly fetch the association."

La seule solution pour forcer le LAZY sur ce cas est d'activer le Bytecode Enhancement :

<enableLazyInitialization>true</enableLazyInitialization>

un proxy hibernate

Un proxy hibernate est un objet qui encapsule l'objet réel et qui permet de retarder le chargement de l'objet.

L'objet proxy est l'objet lui-même mais il ne contient que son identifiant.

Sans identifiant, il ne peut donc créer un proxy

Il a donc besoin de savoir si l'objet existe en base de données avant de pouvoir le charger.


3. Valeurs de l'attribut lazy en HBM

Pour <many-to-one> et <one-to-one constrained="true"> :

Valeur Comportement
lazy="proxy" Défaut — crée un proxy Hibernate, requête émise à l'accès
lazy="no-proxy" Lazy sans proxy — nécessite le Bytecode Enhancement
lazy="false" EAGER — chargement immédiat

Pour les collections (<set>, <list>, …) :

Valeur Comportement
lazy="true" Défaut — collection chargée à l'accès
lazy="false" EAGER — chargement immédiat avec la requête parente
lazy="extra" Smart lazy — count() et contains() sans charger toute la collection

4. Bonnes pratiques sur le Fetch

Recommandation officielle Hibernate :

"Marquer toutes les associations en LAZY statiquement, puis définir les stratégies de chargement dynamiquement selon les besoins via JPQL JOIN FETCH ou @EntityGraph.

Eviter EAGER par défaut

Problème Description
N+1 requêtes Chaque entité chargée déclenche autant de requêtes que d'associations EAGER
Produit cartésien Plusieurs @ManyToMany en EAGER génèrent un produit cartésien explosif
Chargement inutile Des données sont chargées même quand le cas d'usage n'en a pas besoin(ou dans l'autre sens de la relation)

Exemple :

// ❌ À éviter : EAGER statique
@ManyToOne(fetch = FetchType.EAGER)
private Customer customer;

// ✅ Recommandé : LAZY statique 
@ManyToOne(fetch = FetchType.LAZY)
private Customer customer;

// JOIN FETCH dynamique
"SELECT o FROM Order o JOIN FETCH o.customer WHERE o.id = :id"

5. Références

Ressource URL
Hibernate 5.3 User Guide — Associations https://docs.hibernate.org/orm/5.3/userguide/html_single/#associations
Hibernate 5.3 User Guide — Fetching https://docs.hibernate.org/orm/5.3/userguide/html_single/#fetching
Hibernate 3.3 Reference — Basic O/R Mapping (HBM) https://docs.hibernate.org/orm/3.3/reference/en/html/mapping.html
Hibernate 3.3 Reference — Collections (lazy HBM) https://docs.hibernate.org/orm/3.3/reference/en/html/collections.html
FetchType Lazy/Eager — Thorben Janssen https://thorben-janssen.com/entity-mappings-introduction-jpa-fetchtypes/
Mapping Definitions JPA/Hibernate (Annotations vs XML) — Thorben Janssen https://thorben-janssen.com/mapping-definitions-jpa-hibernate-annotations-xml/
A beginner's guide to Hibernate fetching strategies — Vlad Mihalcea https://vladmihalcea.com/hibernate-facts-the-importance-of-fetch-strategy/

Terminé