The JPA property jakarta.persistence.sharedCache.mode accepts ENABLE_SELECTIVE, DISABLE_SELECTIVE, ALL and NONE. Explain what each value means for which entities get cached, and which one you would run in production.
answer
- ENABLE_SELECTIVE = opt-in via @Cacheable (default)
- DISABLE_SELECTIVE = opt-out via @Cacheable(false)
- ALL ignores annotations; NONE disables all
- UNSPECIFIED → Hibernate behaves as ENABLE_SELECTIVE
- NONE = config-only kill switch for tests/incidents
basics
~10 sENABLE_SELECTIVE (the practical default) caches only entities marked @Cacheable. DISABLE_SELECTIVE caches everything except @Cacheable(false). ALL caches every entity regardless of annotations, NONE caches none. Production should use ENABLE_SELECTIVE — opt in deliberately.
solid answer
~50 s`jakarta.persistence.sharedCache.mode` decides how annotations map to actual caching: - **ENABLE_SELECTIVE** — opt-in: only entities annotated `@Cacheable` (or `@Cacheable(true)`) are cached. This is Hibernate's effective default and the right production setting. - **DISABLE_SELECTIVE** — opt-out: everything is cached except entities annotated `@Cacheable(false)`. - **ALL** — every entity is cached, annotations ignored. Useful for a quick experiment or a genuinely read-only reference schema. - **NONE** — nothing is cached even if annotated; the cleanest global kill switch, handy for tests and for isolating a suspected staleness bug. - **UNSPECIFIED** — provider-defined; Hibernate behaves like ENABLE_SELECTIVE. I default to ENABLE_SELECTIVE because caching is a per-entity correctness decision: hot, small, rarely-mutated reference data benefits, while high-churn transactional tables get pure overhead — every write invalidates or updates the region, and hit rates stay low. ALL and DISABLE_SELECTIVE also let a newly added entity silently join the cache, which is exactly the kind of change nobody reviews.
code
properties · 5 lines# production
jakarta.persistence.sharedCache.mode=ENABLE_SELECTIVE
# test profile: infrastructure present, participation off
jakarta.persistence.sharedCache.mode=NONEgo deeper
Know the four values and that the default behaviour is opt-in through @Cacheable.
Explain why opt-in is the right default — write cost, memory, and the reviewability of an explicit annotation.
Bring in operational use: NONE as a per-environment kill switch and as a bisection tool for suspected stale reads.
Position it as governance: caching enrolment should be an explicit, reviewed per-entity decision rather than a global default that new code inherits silently.
## The property's job The second-level cache has two independent gates. One is the infrastructure gate: `hibernate.cache.use_second_level_cache` plus a working `RegionFactory`. The other is the **policy gate**: given that caching is available, which entity types actually participate? That second gate is `jakarta.persistence.sharedCache.mode`, a standard JPA property (spelled `javax.persistence.sharedCache.mode` before the Jakarta rename) that can also be written as `<shared-cache-mode>` in `persistence.xml`. ## The five values **ENABLE_SELECTIVE** — opt-in. An entity is cached only if it carries `@Cacheable` (whose `value` defaults to `true`). Anything unannotated is untouched. This is what almost every real system runs, and it is what Hibernate does when the property is absent. **DISABLE_SELECTIVE** — opt-out. Every entity is cached unless it carries `@Cacheable(false)`. The blast radius is the whole domain model, so a new entity is cached the moment it is written. **ALL** — caches every entity and ignores `@Cacheable` entirely, including `@Cacheable(false)`. Legitimate for a schema that is genuinely reference data (currencies, country codes, tax bands) or for a quick before/after measurement. **NONE** — disables participation for every entity even though the infrastructure is present. Distinct from turning off `use_second_level_cache`: the regions and factory still exist, so you can flip the switch by configuration alone, per environment, without redeploying. That makes it a valuable incident lever and a good test setting. **UNSPECIFIED** — the formal default when nothing is set; the provider decides, and Hibernate treats it as ENABLE_SELECTIVE. ## Why opt-in wins Caching an entity is not free and is not universally correct. *Cost.* Each write to a cached entity must also touch the region — invalidate, or write the new state under a lock, depending on the concurrency strategy. For a table with a high write:read ratio, you pay that on every write and rarely get a hit back. Under an opt-out mode, your busiest write-heavy tables are enrolled by default — exactly backwards. *Memory.* Every cached type consumes a region with its own sizing. Blanket caching an entity with large `@Lob` fields or wide rows can push heap pressure and GC pauses well past whatever query time you saved. *Correctness.* Cached state is only as fresh as your invalidation. If some rows are also written by a batch job, a stored procedure, another service, or Hibernate bulk `UPDATE`/`DELETE` statements, the cache can serve stale values. Deciding that per entity is a conscious act; inheriting it from a global mode is not. *Reviewability.* Under ENABLE_SELECTIVE, `@Cacheable` in a diff is a visible, discussable decision. Under DISABLE_SELECTIVE or ALL, a new entity class joins the cache with no diff at all. ## Interaction with @Cache The mode governs *whether* an entity is cached; Hibernate's `@Cache` governs *how* — concurrency strategy and region. Under ALL, entities without `@Cache` get the strategy from `hibernate.cache.default_cache_concurrency_strategy`, so a blanket mode also blanket-applies a strategy nobody chose per entity. That is another reason to keep the enrolment explicit. ## Practical usage A workable pattern is ENABLE_SELECTIVE everywhere, with NONE in the test profile so tests never depend on cache residency and never leak state between cases. When investigating suspected stale reads in production, switching the mode to NONE is a fast, low-risk bisection: if the anomaly disappears, the cache is implicated; if not, look elsewhere. Keep in mind that `@Cacheable` is not inherited in a useful way across every mapping strategy — for inheritance hierarchies, annotate the root entity, since the cache region is organised by the root type.
- What is the difference between setting the shared-cache mode to NONE and setting hibernate.cache.use_second_level_cache to false?`use_second_level_cache=false` removes the infrastructure: no region factory is used and no regions are created. `NONE` keeps the factory and regions configured but excludes every entity from participating. The practical difference is operational — NONE lets you toggle caching per environment or during an incident without changing the provider wiring, and it fails fast if the provider configuration itself is broken.
- You run with ALL to "cache everything" and throughput gets worse. What is the likely cause?Write-heavy entities are now enrolled, so every insert, update and delete must also maintain the cache region while hit rates on those types stay near zero. Add memory pressure from wide or LOB-bearing entities and you get more GC and less headroom. Statistics per region will show high put counts with negligible hits — that is the signature to look for before reverting to ENABLE_SELECTIVE.
saying these in an interview costs you the question
- Saying ENABLE_SELECTIVE means "Hibernate picks which entities to cache"
- Believing ALL still honours @Cacheable(false)
- Thinking the mode chooses the concurrency strategy — that is @Cache/usage
- Assuming caching more entities is always faster
- Confusing this JPA property with a Spring caching abstraction setting