Which APIs let you remove entries from Hibernate's second-level cache programmatically, and what is the operational risk of the broadest of them?
answer
- emf.getCache(): evict(Class,id) / evict(Class) / evictAll / contains
- sessionFactory.getCache(): entity, collection, natural-id, query regions
- Narrowest correct eviction wins
- evictAll = thundering herd on the database
- Eviction is node-local unless the provider clusters it
basics
~20 sThe portable jakarta.persistence.Cache from the EntityManagerFactory can evict one entity by id, a whole entity type, or everything. Hibernate's own SessionFactory cache adds region-level methods. Evicting everything on a live system sends all traffic straight to the database.
solid answer
~40 sTwo levels of API. The portable one is `entityManagerFactory.getCache()`, a `jakarta.persistence.Cache` with `evict(Class, id)`, `evict(Class)`, `evictAll()` and `contains(Class, id)`. The richer one is Hibernate's `sessionFactory.getCache()`, which exposes `evictEntityData`, `evictCollectionData`, `evictNaturalIdData`, `evictQueryRegion`/`evictQueryRegions` and `evictDefaultQueryRegion`, so you can target exactly the structure you invalidated. The risk is granularity. `evictAll()` on a warm production node turns every subsequent read into a database hit at once: a thundering herd on the database precisely when the cache was doing the most work, and in a cluster each node refills independently. Prefer the narrowest eviction that is correct — a single key after an out-of-band write, one region after a batch job — and treat a full flush as a maintenance action, not something an application code path does routinely.
code
java · 10 lines// Portable JPA
Cache cache = em.getEntityManagerFactory().getCache();
cache.evict(Product.class, 42L);
boolean cached = cache.contains(Product.class, 42L);
// Hibernate-native, finer grained
SessionFactory sf = em.getEntityManagerFactory().unwrap(SessionFactory.class);
sf.getCache().evictEntityData(Product.class, 42L);
sf.getCache().evictCollectionData("com.example.Order.lines");
sf.getCache().evictQueryRegion("reports");go deeper
Name emf.getCache() and its evict/evictAll/contains methods and know eviction just forces the next read to reload from the database.
Add Hibernate's finer-grained methods for collections, natural ids and query regions, and explain why partial eviction can leave an inconsistent read path.
Discuss granularity and timing under load, the refill burst after a broad eviction, and whether eviction propagates across cluster nodes.
Treat manual eviction as an operational contract: who may call it, at what blast radius, with what refill plan, and whether its existence signals an entity that should not be cached.
## The portable API JPA standardises a small cache-control surface reached from the factory: ``` Cache cache = em.getEntityManagerFactory().getCache(); cache.evict(Product.class, 42L); // one entry cache.evict(Product.class); // every Product cache.evictAll(); // the whole second-level cache cache.contains(Product.class, 42L); ``` `contains` is useful in tests and diagnostics: it tells you whether the shared cache currently holds that identifier, which is the honest way to prove caching is actually happening rather than assuming it from a configuration file. ## The Hibernate API Unwrapping to Hibernate gives finer control, because Hibernate stores several distinct kinds of data: ``` CacheImplementor cache = sessionFactory.getCache(); cache.evictEntityData(Product.class, 42L); cache.evictEntityData(Product.class); cache.evictCollectionData(Order.class.getName() + ".lines"); cache.evictNaturalIdData(Product.class); cache.evictQueryRegion("reports"); cache.evictDefaultQueryRegion(); ``` The separation matters: evicting entity data does not evict cached collections that reference it, and cached query results live in their own regions with their own validity rules. A partial eviction that forgets one of these leaves an inconsistent picture, for example a cached collection of identifiers whose entities are gone. ## When you legitimately reach for these - After a job that wrote to the schema outside Hibernate (a loader, an external service, a DBA fix), evict the entity type or the affected keys. - After a native SQL statement whose tables you did not declare as synchronized. - During tests, to prove a read really goes to the database. - On a controlled configuration or reference-data change: evict the region rather than restarting the process. ## Why evictAll is dangerous A full eviction removes the buffer between your application and the database in one step. Every request that was being served from memory now issues SQL, all at the same moment, from every thread. Where the cached entities were hiding an N+1 access pattern, that pattern becomes visible as a flood. Two aggravating factors: in a cluster, an administrative endpoint that evicts all nodes multiplies the burst, and if the eviction happens under load, the refill itself competes with normal traffic and can push latency past timeouts, causing retries that add still more load. Mitigations if you must offer such an operation: expose it only to operators, do it per region, do it during a quiet period, and consider a warm-up read path afterwards. ## Eviction is local unless the provider says otherwise A plain eviction call affects the cache of the JVM that ran it. Whether other nodes hear about it depends entirely on the provider's topology. With a clustered, invalidation-aware provider the removal is broadcast; with independent per-node caches it is not, and "I evicted it" only means "I evicted it here". Any operational procedure built on manual eviction must state which of those it is. ## What interviewers listen for Name the portable API, know that Hibernate has a richer one with separate entity/collection/natural-id/query calls, and show judgement about granularity and cluster scope rather than reaching for `evictAll()` as the answer to every staleness problem.
- You evicted the entity region but stale data still appears in a list screen. What did you miss?Most likely cached collections or cached query results, which live in their own regions and are not removed by entity eviction. A cached collection holds identifiers, and a cached query result holds a key list plus a timestamp; both must be evicted or invalidated separately for the read path to be fully refreshed.
- Does calling evictAll() on one node clear the caches of the other nodes?Only if the cache provider is clustered and propagates removals. With independent per-node caches it clears the local JVM only, which is why administrative eviction endpoints usually have to be called on every node or backed by a provider that broadcasts invalidation.
saying these in an interview costs you the question
- Treating evictAll() as the routine fix for any stale-data report
- Assuming a local eviction is automatically cluster-wide
- Believing entity eviction also clears cached collections and query results
- Thinking there is no portable API and you must always unwrap to Hibernate
- Using cache eviction where the real fix is not caching a volatile entity at all