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 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/ |