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>
La seule solution pour forcer le LAZY sur ce cas est d'activer le Bytecode Enhancement :
<enableLazyInitialization>true</enableLazyInitialization>
Si on doit utiliser le Bytecode Enhancement alors il faudra approfondir ce point et compléter cette section
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 FETCHou@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/ |