title: Hibernate 2nd level cache invalidation when another process modifies the database
body: <p>We have an application that uses Hibernate's 2nd level caching to avoid database hits. </p>
  
  <p>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). </p>
  
  <p>We are using <a href="http://ehcache.org/documentation/hibernate.html" rel="noreferrer">EHCache</a> as our 2nd level cache implementation.</p>
  
  <p>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. </p>
  
  <p>The SessionFactory contains methods to manage the 2nd level cache:
   - <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-sessioncache" rel="noreferrer">Managing the Caches</a></p>
  
  <pre><code>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
  </code></pre>
  
  <p>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.</p>
  
  <pre><code>// 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);
     }
  }
  </code></pre>
  
  <p>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).</p>