Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🧬 Hibernate – ORM avancĂ©, Fetch, Cache, Batch, Logs & Tuning

Guide IDEO-Lab : Hibernate “provider” JPA orientĂ© production (N+1, graphs, batch, cache L2, logs SQL, statistiques, tuning).

1.1

Hibernate vs JPA

SpĂ©cification vs implĂ©mentation, ce qu’Hibernate ajoute.

JPAProviderExtensions
1.2

Session / Persistence Context

Identity map, dirty checking, flush modes, clear/detach.

SessionFlushDirty
1.3

Mapping avancé Hibernate

Types, @Type, JSON, embeddables, converters, inherited mapping.

@TypeCustom typesInheritance
2.1

Fetch strategies

LAZY/EAGER, join fetch, batch fetch, subselect, entity graphs.

FetchN+1Graphs
2.2

N+1 : diagnostic & remédiation

Symptîmes, outils, patterns robustes (DTO, ids page → fetch).

N+1SQL logsPlan
2.3

Batching & bulk

Batch inserts/updates, ordering, flush/clear, bulk JPQL & stale context.

BatchFlush/ClearBulk
3.1

Cache L2 & query cache

Regions, invalidation, JCache, Ehcache, coherence trade-offs.

L2JCacheRegions
3.2

Locks & Concurrency

@Version, optimistic/pessimistic, timeouts, deadlocks, retries.

OptimisticPessimisticRetries
3.3

SQL généré & logs

Afficher SQL + bind params, slow queries, explain workflow.

SQLBindExplain
4.1

Statistics & profiling

Hibernate Statistics, metrics par endpoint, query count, hotspots.

StatsMetricsHotspots
4.2

Schema & migrations

ddl-auto, naming, Flyway/Liquibase, production discipline.

DDLFlywayNaming
5.1

Cheat-sheet Hibernate

Rappels express : fetch, batching, cache, logs, tuning, piĂšges.

cheatbest practices
1.1 Hibernate vs JPA
JPA = spec, Hibernate = moteur

JPA dĂ©finit des annotations + l’API (EntityManager). Hibernate est une implĂ©mentation (provider) qui ajoute des options de tuning, caches, statistics, types, fetch controls plus riches.

RĂšgle : rester JPA “standard” pour la majoritĂ© du code, utiliser Hibernate-specific sur les points critiques.
Where Hibernate matters most
  • N+1 (fetch tuning)
  • Batching writes
  • Second-level cache & regions
  • Custom types (JSON, enums, arrays)
  • Statistics for profiling
Extensions utiles (exemples)
FeatureUsageValue
Batch fetchingcharger plusieurs collections lazy en INréduit N+1
Statisticscompteurs queries / hits cacheprofiling
Custom typesJSON, arrays, moneymapping clean
Second-level cacheread-heavylatence ↓
RĂšgles de production (simple et strict)
  • Disable Open Session In View (sinon lazy partout).
  • Mesurer “queries per request” (dĂ©tecter N+1).
  • Batch + flush/clear en traitement massif.
  • Cache L2 uniquement si invalidation maĂźtrisĂ©e.
  • Migrations via Flyway/Liquibase (ddl-auto validate/none).
# English-only sample
spring.jpa.open-in-view=false
spring.jpa.hibernate.ddl-auto=validate
1.2 Session / Persistence Context
Identity map (L1) : mĂȘme ID → mĂȘme instance

Dans une session, Hibernate garantit l’identitĂ©. C’est utile (cohĂ©rence) mais ça peut gonfler en mĂ©moire sur des traitements bulk.

// English-only conceptual states
transient -> persistent(managed) -> detached
             | remove()
             v
           removed
Flush = pousser SQL vers la DB

Flush ne commit pas forcément. Il envoie les INSERT/UPDATE/DELETE.

// English-only note
FlushMode.AUTO: flush before query if needed
FlushMode.COMMIT: flush only on commit
FlushMode.MANUAL: explicit flush() only
PiĂšge : une query JPQL peut dĂ©clencher un flush implicite (AUTO), donc du SQL “surprise”.
clear() / detach() : contrÎler la mémoire
// English-only sample
for (int i = 0; i < items.size(); i++) {
  session.persist(items.get(i));
  if (i % 100 == 0) {
    session.flush();
    session.clear();
  }
}

La paire flush+clear est ton outil principal en bulk writes.

1.3 Mapping avancé Hibernate (Types, JSON, Converters)
Pourquoi des types custom ?
  • Garder un modĂšle mĂ©tier propre (Money, Email, JsonBlob
).
  • Eviter des hacks de colonnes et conversions dispersĂ©es.
  • Centraliser validation + sĂ©rialisation.
// English-only sample (JPA converter pattern)
@Converter
public class MoneyConverter implements AttributeConverter {
  public Long convertToDatabaseColumn(Money v) { return v == null ? null : v.cents(); }
  public Money convertToEntityAttribute(Long v) { return v == null ? null : Money.ofCents(v); }
}
Precision & numeric pitfalls
  • Monnaie : BigDecimal ou cents (Long) selon le besoin.
  • Fixer precision/scale au niveau DB et mapping.
  • Enums : toujours string pour stabilitĂ©.
// English-only sample
@Enumerated(EnumType.STRING)
@Column(nullable=false, length=32)
private Status status;
JSON : le vrai choix = usage + index
ApproachGood forTrade-off
JSON columnflex fieldsneeds JSON indexes for search
Normalized tablesquery-heavymore joins
Serialized blobwrite-heavyno query on fields
Important : si tu requĂȘtes sur du JSON → pense index (GIN/functional) cĂŽtĂ© DB.
2.1 Fetch strategies (LAZY/EAGER, join fetch, batch, graphs)
Fetch : le sujet #1 Hibernate en prod
  • EAGER par dĂ©faut sur certains mappings = surprises.
  • LAZY partout, puis charger explicitement ce qu’il faut.
  • DTO projections = stable pour API.
Rùgle : charge “just enough data” dans la transaction du Service.
JOIN FETCH (ciblé)
// English-only sample
List orders =
  em.createQuery(
    "select distinct o from Order o " +
    "left join fetch o.lines " +
    "where o.status = :s", Order.class)
  .setParameter("s", "OPEN")
  .getResultList();

Prudence : join fetch d’une collection + pagination = souvent problĂ©matique.

Batch fetching
# English-only sample
hibernate.default_batch_fetch_size=50

Quand une collection lazy est demandée, Hibernate charge plusieurs parents via IN.

EntityGraph (fetch plan explicite)
// English-only sample
EntityGraph graph = em.createEntityGraph(Order.class);
graph.addAttributeNodes("customer");
Subgraph sg = graph.addSubgraph("lines");
sg.addAttributeNodes("product");
Pattern robuste : pagination sur IDs (page) → fetch graph sur ces IDs.
2.2 N+1 : diagnostic & remédiation (workflow DBA-like)
SymptĂŽmes typiques
  • Latence qui explose avec le nombre d’items.
  • Logs SQL “mitraillette” (des centaines de SELECT).
  • Pool DB saturĂ© (threads en attente de connexion).
// English-only minimal N+1 example
List orders = em.createQuery("select o from Order o", Order.class).getResultList();
for (Order o : orders) { o.getLines().size(); }
Outils de diag (indispensables)
  • Logs SQL + bind params (temporaire, en debug).
  • Compteur de requĂȘtes par requĂȘte HTTP (AOP / metrics).
  • Slow query log DB + EXPLAIN plans.
# English-only sample
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.orm.jdbc.bind=TRACE
Patterns qui tiennent la route
PatternQuandImpact
DTO projectionAPI/readsdata minimal + stable
JOIN FETCHpetit graphequeries ↓
EntityGraphfetch planpilotage propre
IDs page → fetchpaginationĂ©vite duplicates/cartesian
Batch fetch sizelazy collectionsIN queries
RĂšgle d’or : tu dois ĂȘtre capable d’expliquer “combien de requĂȘtes” pour un endpoint.
2.3 Batching & bulk (writes massifs)
Config batching (Hibernate)
# English-only sample
hibernate.jdbc.batch_size=50
hibernate.order_inserts=true
hibernate.order_updates=true
hibernate.jdbc.batch_versioned_data=true

Ces options améliorent fortement le throughput en insert/update.

Pattern flush/clear
// English-only sample
for (int i = 0; i < items.size(); i++) {
  session.persist(items.get(i));
  if (i % 100 == 0) {
    session.flush();
    session.clear();
  }
}
Pourquoi : réduire mémoire + accélérer dirty checking + stabiliser la latence.
Bulk JPQL : attention au contexte

Les bulk updates bypass le persistence context : les entitĂ©s dĂ©jĂ  chargĂ©es deviennent “stale”.

// English-only sample
int n = em.createQuery("update Customer c set c.status = :s where c.lastLogin < :d")
  .setParameter("s", "INACTIVE")
  .setParameter("d", cutoff)
  .executeUpdate();
em.clear();
3.1 Cache L2 & Query Cache
Quand L2 cache vaut le coup
  • Read-heavy, reference data, faible taux de modification.
  • Hot entities consultĂ©es trĂšs souvent.
  • Latence DB non nĂ©gligeable.
Si la donnĂ©e bouge beaucoup : L2 peut coĂ»ter plus qu’il ne rapporte (invalidation churn).
Config (ex JCache)
# English-only sample
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.jcache.JCacheRegionFactory
hibernate.javax.cache.provider=org.ehcache.jsr107.EhcacheCachingProvider

La configuration réelle dépend du provider cache (Ehcache/Infinispan
).

Invalidation : le point critique
ApproachProCon
Read-only regionsfastmust truly be immutable
Read-write regionssafemore overhead
No cachesimpleDB load
3.2 Locks & Concurrency (@Version, pessimistic, timeouts)
Optimistic locking (scalable)
// English-only sample
@Version
private long version;

Excellent en faible contention : collisions gérées par retry.

Pessimistic lock
// English-only sample
Account a = em.find(Account.class, id, LockModeType.PESSIMISTIC_WRITE);

À rĂ©server aux hot rows critiques, TX courte, timeouts stricts.

Retry policy (must-have)
// English-only pseudo
for (int attempt = 1; attempt <= 3; attempt++) {
  try { doWork(); break; }
  catch (OptimisticLockException e) { sleep(backoff(attempt)); }
}
Mesurer : collision rate + p95 latency, sinon tu voles à l’aveugle.
3.3 SQL généré & logs (bind params, slow queries, explain)
Afficher SQL (temporaire)
# English-only sample
logging.level.org.hibernate.SQL=DEBUG

En prod, préférer sampling + slow query log DB.

Voir les bind parameters
# English-only sample
logging.level.org.hibernate.orm.jdbc.bind=TRACE
Attention : binds peuvent contenir des donnĂ©es sensibles → ne pas laisser activĂ© en prod.
Workflow “DBA-like”
  1. Capturer la requĂȘte rĂ©elle (avec binds ou valeurs).
  2. Rejouer en SQL client.
  3. EXPLAIN ANALYZE (ou plan équivalent).
  4. Corriger : index / rewrite / fetch plan / pagination.
  5. Re-mesurer (p95/p99 + query count).
4.1 Hibernate Statistics & profiling
Enable statistics
# English-only sample
hibernate.generate_statistics=true

Utilise en staging, ou ponctuellement en prod (avec prudence) pour diagnostiquer.

Ce que tu veux voir
  • Query count / entity load count.
  • L2 cache hit/miss.
  • Collection fetch count (detect N+1).
Objectif : “une requĂȘte HTTP doit avoir une enveloppe query count connue”.
KPIs par endpoint
  • p95/p99 latency
  • db time vs app time
  • queries/request
  • pool wait time
// English-only concept
request_id -> controller -> service -> repo
  metrics: queries, db_ms, total_ms
4.2 Schema & migrations (ddl-auto, naming, Flyway/Liquibase)
Discipline production
  • ddl-auto : validate/none
  • migrations versionnĂ©es (Flyway/Liquibase)
  • review + tests sur dataset rĂ©aliste
# English-only sample
spring.jpa.hibernate.ddl-auto=validate
Naming & index strategy
  • Fixer naming strategy pour Ă©viter drift.
  • Index design cĂŽtĂ© migrations, pas via annotations “au petit bonheur”.
  • Sur DB : monitor index bloat / unused indexes.
Rule : schema is code (versioned), not runtime side effects.
5.1 Cheat-sheet Hibernate (prod)
Fetch / N+1
// English-only quick notes
Disable open-in-view
Prefer DTO projections for API
Use join fetch for small graphs
Use EntityGraph for explicit fetch plan
For pagination: page IDs then fetch graph
Enable batch fetch size to reduce N+1
Batching
// English-only quick notes
hibernate.jdbc.batch_size=50
hibernate.order_inserts=true
hibernate.order_updates=true
flush+clear every N
Bulk updates -> clear() after
Cache / Logs / Stats
// English-only quick notes
Use L2 cache only with clear invalidation rules
Track cache hit/miss
SQL logs + bind only for debug (sensitive)
Use slow query log + explain plans
Enable generate_statistics for profiling
Concurrency
// English-only quick notes
Use @Version for optimistic locking
Implement retry with backoff
Use pessimistic locks only when needed
Keep transactions short