| name | java-jpa-hibernate-performance |
| description | Use this skill when statically reviewing JPA/Hibernate data access for fetch-strategy correctness and reliability — N+1 exposure, JOIN FETCH vs @EntityGraph vs @BatchSize vs DTO projection, LazyInitializationException and open-in-view misuse, pagination combined with a collection fetch (cartesian product), MultipleBagFetchException, and HikariCP connection-pool sizing. Trigger when a user provides entity classes, mappings, Spring Data repositories, or JPQL/Criteria queries and asks why queries are slow, why a page loads too much, or whether their data access is correct. Reads source and mapping only; it never opens a database connection, runs a query, or executes migrations. |
| allowed-tools | Read Grep Glob |
| metadata | {"author":"github: Raishin","version":"0.1.0","updated":"2026-07-17","category":"database","lifecycle":"experimental"} |
Java JPA/Hibernate Performance Review
Purpose
This skill statically reviews JPA/Hibernate data access for fetch-strategy correctness, query shape, and connection reliability. Data access is only sound if associations are fetched by explicit, access-shaped strategies rather than lazy-by-accident or eager-by-default, if pagination does not silently load a cartesian product into memory, if the request is not leaning on open-in-view to resolve lazy state in the view layer, and if the connection pool is sized from measured hold time rather than a round number. The review catches N+1 patterns, eager collections, pagination-with-fetch, MultipleBagFetchException risk, open-in-view misuse, and mis-sized HikariCP pools.
Trigger conditions
- A user provides entity classes and mappings, Spring Data repositories, or JPQL/Criteria/HQL queries.
- A user asks why ORM queries are slow, why a page returns far more rows than expected, or why they get a
LazyInitializationException.
- A user wants a static review of their persistence layer before merge or release.
When not to use
- The task is
@Transactional boundary, propagation, or isolation correctness — route to the transaction and consistency agent.
- The task is schema-migration deploy safety (Flyway/Liquibase) — route to the migration agent.
- The task is raw-SQL injection surface — route to the security agents.
Lean operating rules
- HIGH — treat an N+1 access pattern as a defect: an association traversed in a loop, a lazy association accessed per row on a request path, or a derived query returning entities whose associations are then walked. Recommend
JOIN FETCH, an @EntityGraph, @BatchSize, or a DTO projection — chosen by the access shape, not reflexively.
- HIGH — treat
FetchType.EAGER on a collection (@OneToMany/@ManyToMany) as a defect; it forces the association on every load and defeats query-specific tuning. Default collections to LAZY and fetch explicitly.
- HIGH — treat pagination combined with a collection
JOIN FETCH (setMaxResults/Pageable over a fetched bag) as a defect: Hibernate cannot paginate in the database and loads the full cartesian product into memory (HHH000104). Recommend a two-query approach (page IDs, then fetch) or @BatchSize.
- HIGH — treat two
JOIN FETCH-ed List/bag collections in one query as a MultipleBagFetchException risk; recommend Set semantics or separate queries.
- HIGH — treat
spring.jpa.open-in-view=true (or left unset in a web app) leaned on so lazy associations resolve in the view as an anti-pattern that holds the connection for the whole request and hides N+1. Recommend explicit fetching plus open-in-view=false, and flag any LazyInitializationException "fix" that just re-enables OIV.
- MEDIUM — treat a HikariCP
maximumPoolSize set without reference to database max_connections, instance count, and per-request connection hold time as a sizing risk; recommend sizing from measured hold time and flag missing connectionTimeout/leakDetectionThreshold.
- MEDIUM — treat entities loaded and mutated only to read a few fields as wasted hydration; recommend a DTO/interface projection for read-only paths.
- LOW — treat
hibernate.jdbc.batch_size unset on a bulk path as a batching miss.
- Never recommend disabling lazy loading globally, blanket
EAGER fetching, or re-enabling open-in-view to silence LazyInitializationException; never recommend a second-level cache to paper over N+1 without stating the consistency trade-off; never recommend disabling a failing gate.
- Base every conclusion on the mapping + query evidence provided; a fetch-strategy claim without the mapping or the query site is or — say so.
References
Load these only when needed:
- Fetch-strategy and pool evidence — the decision guide for N+1 remediation (JOIN FETCH vs @EntityGraph vs @BatchSize vs DTO), pagination-with-fetch, open-in-view, and HikariCP sizing, with the evidence each conclusion needs.
- Workflow and output contract — the step-by-step review, the evidence checklist, the findings rubric, and the output format.
Response minimum
Return, at minimum:
- A verdict (pass / pass-with-conditions / block) and an evidence level (which mappings, queries, and configuration were provided).
- Fetch-strategy findings (N+1, eager collections, pagination-with-fetch, MultipleBagFetch, projections).
- Open-in-view / LazyInitialization findings.
- Connection-pool (HikariCP) sizing findings.
- A severity-labelled finding list (critical / high / medium / low), each with an evidence-basis label.
- Safe next actions and open questions.