Skip to main content

jpa-hibernate-performance

Specializes in Java Persistence performance (JPA/Hibernate) based on High-Performance Java Persistence (Vlad Mihalcea). Covers JDBC batching, the N+1 query problem and fetch strategies (JOIN FETCH, EntityGraph), FlushOperationQueue and ActionQueue, dirty checking, first- and second-level caching (read-through/nonstrict-read-write), optimistic and pessimistic locking, efficient pagination (keyset vs OFFSET), transactions and isolation, and per-database SQL tuning (EXPLAIN, execution plans).

Source facts

Repository
dandgabr/Coacus
Last source activity
September 20, 2026 at 03:33
Detected SKILL.md language
English
Stars
4
Forks
3

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
5 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
jpa-hibernate-performance
description
Specializes in Java Persistence performance (JPA/Hibernate) based on High-Performance Java Persistence (Vlad Mihalcea). Covers JDBC batching, the N+1 query problem and fetch strategies (JOIN FETCH, EntityGraph), FlushOperationQueue and ActionQueue, dirty checking, first- and second-level caching (read-through/nonstrict-read-write), optimistic and pessimistic locking, efficient pagination (keyset vs OFFSET), transactions and isolation, and per-database SQL tuning (EXPLAIN, execution plans).
# AI Skill: High Performance in Java Persistence (JPA/Hibernate) This skill guides the artificial intelligence to design the Java/JPA persistence layer with a focus on performance, based on *High-Performance Java Persistence* (Vlad Mihalcea), covering raw JDBC, JPA, and Hibernate. --- ## 🧱 1. Persistence Layer Architecture - **Deliberate choice of tool**: raw JDBC batching for ETL/bulk; JPA+Hibernate for domain OLTP; native SQL/projections for analytical queries — **do not force an ORM on everything**. - **Access stereotypes**: domain entities (aggregates with short transactions), DTO projections (read queries), value types (immutable embeddables). - **Short transactions**: the transaction scope equals the smallest atomic unit; never run UI or remote calls inside an open transaction. --- ## 🔥 2. The N+1 Problem and Fetch Strategies ### Diagnosis - **N+1**: one query for the root entity plus N lazy queries while navigating associations; detect it with `hibernate.generate_statistics=true`, `nullSafeGet`/SQL log, and hydration tests. ### Mitigations (in order of preference) 1. **JOIN FETCH** in JPQL: `SELECT a FROM Author a JOIN FETCH a.books WHERE a.id = :id` — a single round-trip fetch. 2. **@EntityGraph**: declarative definition of the fetch plan per use case (without polluting queries). 3. **`@_BATCH(size)` / `hibernate.default_batch_fetch_size`**: turn N queries into N/size `IN (...)` queries — the best balance for arbitrary associations. 4. **`@Fetch(FetchMode.SUBSELECT)`**: for collections accessed in bulk within the same transaction. 5. **`@BatchSize`** on lazy collections; `@LazyCollection(LazyCollectionOption.EXTRA)` for count-only. ### Rules - `FetchType.LAZY` on **every** association (the safe default); a UNI-side `@ManyToOne(optional=false)` may be EAGER with justification. - Never use "open session in view" in production — the classic villain of N+1 and long transactions. - For large many-to-many, prefer **two unilateral bidirectional** associations with an extra `@LazyCollection(ExtraLazyType)`. Access them through a DTO when the write model does not need the collection. --- ## 📦 3. Write-Behind, Flush, and Batching ### ActionQueue and Flush Order - Hibernate orders operations in the `ActionQueue` (inserts → updates → collection removes → deletions), already designed for FK/UNIQUE; understand the order in multi-entity transactions. - `FlushModeType.AUTO` flushes on queries "[flush before a query that may touch pending data]"; use `COMMIT` for read-only hot paths and control the flush manually (`em.flush()`). ### JDBC Batching - Enable: `hibernate.jdbc.batch_size` (30–50 typical), `order_inserts=true`, `order_updates=true`, `batch_versioned_data=true`. - **Driver requirement**: `rewriteBatchedStatements` (MySQL), `reWriteBatchedInserts` (PostgreSQL) for a real batch on the wire. - **IDENTITY disables insert batching** (Hibernate needs the generated id); prefer `SEQUENCE` (with `allocationSize` 50+) or `TABLE` with a pooler (pooled-lo). - Bulk: `JPQL/HQL bulk update+delete` (they bypass the persistence context), `StatelessSession`, or `Session.doWork` with direct JDBC for large volumes. ### Dirty Checking and State - Default dirty checking scans the context's entities; for large or read-only entities use `@Immutable` or `Session.refresh`. - `@DynamicUpdate` generates an UPDATE only for the changed columns (less traffic, avoids overwriting) — beware of less cacheable query plans. - Limit the **size of the Session/Persistence Context**: `clear()`/`detach()` in long loops; measure with `em.getEntityManagerFactory().getPersistenceUnitUtil()` and statistics. --- ## 🗄️ 4. Cache (L1, L2, and Query Cache) | Cache | Scope | Recommended use | | :--- | :--- | :--- | | **First-level (Session)** | Transaction/Session | Identity and object caching; always on | | **Second-level (L2)** | SessionFactory (multi-session) | Read-mostly data, references; use TTL/versioning | | **Query cache** | Query result | Only with few results and stable tables (invalidation is costly) | - **Concurrency strategies** (from strictest to lightest): `READ_WRITE` → `NONSTRICT_READ_WRITE` → `READ_ONLY`. - `NONSTRICT_READ_WRITE`: a light asynchronous lock; fine for read-mostly; never under high concurrent write (it invalidates too much). - **Providers**: JCache (Ehcache 3, Infinispan, Caffeine bridge); size L2 regions to the working set (do not "cache everything"). - **Read-through in the app**: an explicit Cache-Aside pattern ([system-design-scalability](../../engineering/practices/system-design-scalability/SKILL.md)) often beats L2 when the domain suits it. --- ## 🔒 5. Locking, Concurrency, and Transactions - **Optimistic (version/numeric)**: handle `OptimisticLockException` with a retry (short transaction); ideal for medium to low contention. Increment the version manually in bulk actions. - **Pessimistic**: `PESSIMISTIC_WRITE` (SELECT FOR UPDATE) for job queues, critical counters, bid/reserve stock; keep lock time minimal. - **Lost update**: the biggest silent plague — a reader and a writer in separate transactions; mitigations: optimistic locking, `PESSIMISTIC_FORCE_INCREMENT`, or atomicity in SQL (`UPDATE ... SET x = x + 1`). - **Isolation**: READ_COMMITTED plus versioning solves 90%; SERIALIZABLE only with good justification (cost in locks and anomalies even in Postgres SSI). --- ## 📑 6. Pagination and Queries - **OFFSET degrades badly** (it scans and discards): for deep pagination use **keyset/seek** (`WHERE (a.id > :last) ORDER BY a.id LIMIT :n`) — constant cost. - Modern standard SQL: `OFFSET ? ROWS FETCH FIRST ? ROWS ONLY` (SQL:2008); dialects vary — let Hibernate map it. - **Projections**: `SELECT new com.x.Dto(...)` for reads (against the traffic of managed entities); `Tuple`/interface-based projections for flexibility. - **Criteria API** for dynamic filters; beware of generating non-cacheable plans (use the query plan cache with constant parameters). - Measurement per database: `EXPLAIN (ANALYZE, BUFFERS)` (Postgres), `set showplan` (SQL Server), autotrace (Oracle) — validate the plan before and after ([db-postgresql](../db-postgresql/SKILL.md)). --- ## 🧭 7. Persistence Optimization Protocol 1. **Measure first**: `hibernate.generate_statistics=true` in dev; APM in prod; identify N+1, repeated queries, long sessions. 2. **Fix the fetch** (JOIN FETCH/EntityGraph) before touching the cache. 3. **Enable batching** and verify the wire (driver logs) — a batch that never reaches the database is pure overhead. 4. **Cache with policy**: L2 for read-mostly with TTL/versions; query cache rarely. 5. **Locking per case**: optimistic by default; pessimistic only for micro-intervals. 6. **Keyset pagination**; OFFSET only for small initial pages. 7. **Load tests** with realistic data (cardinality and skew) and verification of plans after index changes or migration. 8. **Django-like providers**: keep the driver and dialect up to date (optimizations arrive with each Hibernate/JDBC driver version). --- ## 🔗 Integration with Other Skills - [lang-java](../../languages/lang-java/SKILL.md): JPA fundamentals under concurrency and the JVM. - [db-postgresql](../db-postgresql/SKILL.md), [db-mariadb](../db-mariadb/SKILL.md), [db-sqlite](../db-sqlite/SKILL.md): tuning the target database (EXPLAIN, indexes, buffer). - [dba-database-administrator](../../roles/dba-database-administrator/SKILL.md): modeling, indexes, and reference queries. - [backend-developer](../../roles/backend-developer/SKILL.md): integration into Java services/APIs with short transactions. - [latency-engineering](../../engineering/practices/latency-engineering/SKILL.md): connection-pool round-trips and N+1 as p99 villains.
View on GitHub