Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate 2nd level cache invalidation when another process modifies the database

We have an application that uses Hibernate's 2nd level caching to avoid database hits.

I was wondering if there is some easy way to invalidate the Java application's Hibernate 2nd level cache when an outside process such as a MySQL administrator directly connected to modify the database (update/insert/delete).

We are using EHCache as our 2nd level cache implementation.

We use a mix of @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) and @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE), and we don't have Optimistic concurrency control enabled using timestamps on each entity.

The SessionFactory contains methods to manage the 2nd level cache: - Managing the Caches

sessionFactory.evict(Cat.class, catId); //evict a particular Cat sessionFactory.evict(Cat.class);  //evict all Cats sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections 

But because we annotate individual entity classes with @Cache, there's no central place for us to "reliably" (e.g. no manual steps) add that to the list.

// Easy to forget to update this to properly evict the class public static final Class[] cachedEntityClasses = {Cat.class, Dog.class, Monkey.class}  public void clear2ndLevelCache() {   SessionFactory sessionFactory = ...   //Retrieve SessionFactory     for (Class entityClass : cachedEntityClasses) {        sessionFactory.evict(entityClass);    } } 

There's no real way for Hibernate's 2nd level cache to know that an entity changed in the DB unless it queries that entity (which is what the cache is protecting you from). So maybe as a solution we could simply call some method to force the second level cache to evict everything (again because of lack of locking and concurrency control you risk in progress transactions from "reading" or updating stale data).

like image 360
Dougnukem Avatar asked Oct 21 '09 21:10

Dougnukem


People also ask

Which 2nd level cache is better in Hibernate?

Hibernate second level cache uses a common cache for all the session object of a session factory. It is useful if you have multiple session objects from a session factory. SessionFactory holds the second level cache data. It is global for all the session objects and not enabled by default.

What is the difference between Level 1 cache and Level 2 cache in Hibernate?

The primary difference is that the first level cache is maintained at the Session level while the second level cache is maintained at the SessionFactory level. The data stored in the first level cache is accessible to the only Session that maintains it, while the second level cache is accessible to all.

How do I invalidate cache in Hibernate?

But Hibernate invalidates the 2nd level cache if you execute an SQL UPDATE or DELETE statement as a native query. This is necessary because the SQL statement changed data in the database, and by that, it might have invalidated entities in the cache. By default, Hibernate doesn't know which records were affected.


1 Answers

Based on ChssPly76's comments here's a method that evicts all entities from 2nd level cache (we can expose this method to admins through JMX or other admin tools):

/**  * Evicts all second level cache hibernate entites. This is generally only  * needed when an external application modifies the game databaase.  */ public void evict2ndLevelCache() {     try {         Map<String, ClassMetadata> classesMetadata = sessionFactory.getAllClassMetadata();         for (String entityName : classesMetadata.keySet()) {             logger.info("Evicting Entity from 2nd level cache: " + entityName);             sessionFactory.evictEntity(entityName);         }     } catch (Exception e) {         logger.logp(Level.SEVERE, "SessionController", "evict2ndLevelCache", "Error evicting 2nd level hibernate cache entities: ", e);     } } 
like image 142
Dougnukem Avatar answered Sep 28 '22 07:09

Dougnukem