Guide to Hibernate Second Level Cache

Caching is the facility provided by ORM frameworks that helps the users to get fast-running web applications while helping the framework itself to reduce the number of queries made to the database in a single transaction.

1. Caching in Hibernate

Hibernate also provides caching functionality in two layers.

  • First-level Cache: This is enabled by default and works in Session scope. It has been explained in detail in this article.
  • Second-level Cache: This is separate from the first-level cache and is available to be used globally in SessionFactory scope.

The above definitions can be understood as that:

  • the entities stored in the second level cache will be available to all the sessions created using that particular session factory.
  • once the SessionFactory is closed, all cache associated with it die and the cache manager also closes down.
  • if we have two instances of SessionFactory (highly discouraged), we will have two cache managers in our application and while accessing cache stored in a physical store, we might get unpredictable results like cache-miss.
hibernate first and second level cache_example
Hibernate first and second level cache

In this tutorial, I am giving concepts around hibernate second-level cache and giving examples using code snippets.

2. How does Second Level Cache Work in Hibernate?

Let us write all the facts point by point to better understand the internal working related to second-level caches.

  1. Whenever hibernate session tries to load an entity, the very first place it looks for a cached copy of the entity in first-level cache (associated with a particular hibernate Session).
  2. If a cached copy of the entity is present in first-level cache, it is returned as the result of load() method.
  3. If there is no cached entity in the first-level cache, then the second-level cache is looked up for the cached entity.
  4. If second-level cache has the cached entity, it is returned as the result of load() method. But, before returning the entity, it is stored in first level cache also so that the next invocation to load() method for that entity will return the entity from the first level cache itself, and there will not be need to go to the second level cache again.
  5. If the entity is not found in first level cache and second level cache also, then a database query is executed and the entity is stored in both cache levels, before returning as the response to load() method.
  6. Second-level cache validates itself for modified entities if the modification has been done through hibernate session APIs.
  7. If some user or process makes changes directly in the database, there is no way that the second-level cache update itself until “timeToLiveSeconds” duration has passed for that cache region. In this case, it is a good idea to invalidate the whole cache and let hibernate build its cache once again. You can use sessionFactory.evictEntity() in a loop to invalidate the whole Hibernate second-level cache.
/**
 * Evicts all second level cache hibernate entites. This is generally only
 * needed when an external application modifies the 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);
    }
}

3. Demo

To understand more using examples, I wrote an application for testing in which I configured EhCache as 2nd level cache. Lets see various scenarios:

3.1. Entity is Fetched for the First Time

DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 0

Explanation: Entity is not present in either 1st or 2nd level cache so, it is fetched from the database.

3.2. Entity is Requested Again in Same Session

//Entity is fecthed very first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 0

Explanation: Entity is present in the first-level cache so, it is fetched from the second-level cache. No need to go to the second-level cache.

3.3. Entity is Evicted from First-level Cache and Requested Again

//Entity is fecthed very first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//Evict from first level cache
session.evict(department);

department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 1

Explanation: First time entity is fetched from the database that causes it to store in 1st and 2nd level cache. Second load() call fetched from first-level cache. Then we evicted the entity from 1st level cache.

So third load() call goes to second level cache and getSecondLevelCacheHitCount() returns 1.

3.4. Entity is Requested Again in Another Session

//Entity is fecthed very first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//Evict from first level cache
session.evict(department);

department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

department = (DepartmentEntity) anotherSession.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 2

Explanation: When another session created from the same session factory tries to get the entity, it is successfully looked up in the second-level cache and no database call is made.

So now we are clear on how second-level cache is used by hibernate.

Happy Learning !!

Was this post helpful?

Join 7000+ Awesome Developers

Get the latest updates from industry, awesome resources, blog updates and much more.

* We do not spam !!

73 thoughts on “Guide to Hibernate Second Level Cache”

  1. why case a and case b have equal output 1 for getEntityFetchCount() method? while in case an entity is fetched from the database and in case b entity is fetched from first level cache still getEntityFetchCount() method has the same output 1. Please clarify for this one

    Reply
  2. When I use @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) for pojo class then there is problem occours.
    when I evict entity from session then it get removed from 1st level cache it’s fine but when I again fetch it then query get fire. I check that entity is present in 2nd level cache but still query get fire.
    If I use @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) then it works fine.
    please help me to understand it

    Reply
  3. Hi I have one question like
    why hibernate is not given any implementation for second level cache.
    As we have so many third party providers EHCache, OSCache, SwarmCache, JBoss Cache 1.x
    Is there any specific reason for this.
    Can you please help me out understanding this

    Thanks
    Vijay

    Reply
  4. Very useful.

    One clarification, when we there is an entity in second level cache ( say for ex: Table1 ) and when I fire HQL like
    HibernateSEssion.query(“update Table1 set col1= value ….”). Will this update the object in second level cache ?

    Reply
  5. Nice and very simple to understand articles. Do you have any article explaining Hibernate architecture? Also do you have any article explaining of hibernate does fetching of many records say hundred thousands of records with loadAll() using threads?

    Reply
  6. when or how does the cacheget invalidated?
    example : I retrieve an emp object from the database with max salary
    and doing some work on the entity. while there is a batch tat onboards new employees and adds a new max to the table.

    if i am in the same session, hibernate sends the result from the fiirst or second level cache.
    so what is the indicator here ? how does it know to refresh apart from time to live attr?

    Reply
    • Any application, which is going to be used by a large group of users, is supposed to have caching enabled. Applications usually execute a lot of similar data to different type of users. If you fetch this data from database every time from database, then database will become heavily loaded and busy. To share the load, second lvl caching comes into picture. It stores data inform of indexes mostly into physical filesystem very near to server itself. So data retrieval time comes down drastically and results into higher performance.

      Reply
    • Hi Narasimhulu,

      I guess, In real world it will be useful in multi-threaded batch applications. Were multiple threads access same table. So if one thread as fetched data from the table, other threads using different sessions need not make db calls but instead fetch from ehcache.

      Lokesh correct me if I am wrong. I can try it and share an example.

      Thanks.

      Reply
  7. I have set up 2nd level cache in our application.For the first call it fetches from the database and for the 2nd call it gets from cache(found out from postgres logs).The issue is if the object has boolean attributes these attributes has null when fetched from cache though there value is true/false.Does any one faced this issue please let me know. Strucked with this for almost 4 days and did not find the solution

    Reply
    • I found the issue.We have defined custom User Types for these boolean attributes.These custom user types has to implement dissemble and assemble functions which are used using caching.We were returning null for these two functions which were causing issue.When i modified it to return the values it takes as in parameters it started working normally.

      Reply
  8. Shouldn’t this be session.get instead of session.load? The latter returns a proxy object with id attached and does not hit the database whereas the former (i.e. get) always hits the database if not found in cache.

    Please correct me if wrong.

    Reply
    • session.load() return the proxy object but if row doesn’t exist it will throw ObjectNotFoundException whereas session.get() return null. For above example, both will produce the same result.

      Reply
  9. Hi Lokesh, I want create a new session factory based on some data extracted from database at runtime and close current sessionfactory. What sholud I do in this case? Please correct me if I am wrong.

    Reply
  10. Hi Lokesh,
    I have configured ehcache as you have depicted in your “Configuring ehcache post”. But In my cache it fails to load ehcache.xml . This is why by default it is picking “ehcache-1.2.3.jar!/ehcache-failsafe.xml”.
    Please suggest where should I keep ehcache.xml to get it loaded and considered.

    Reply
    • Place it anywhere in classpath i.e. “/WEB-INF/classes” folder. Or configure here: <property name=”net.sf.ehcache.configurationResourceName”>/ehcache.xml</property>

      Reply
      • Hi Lokesh,
        I have put this line in hibernate.cfg.xml “/ehcache.xml”. Accordingly also placed ehcache.xml at the same level as that of hibertnate.cfg.xml. But again its not picking this file and going to default file. In my case I am running program from eclipse directly so there is no place for “/WEB-INF/classes” folder. Please suggest how can I get ehcache.xml file noticed.

        Reply
        • Thanks Lokesh,
          I got it configured and running. Now its picking my ehcahce.xml.
          Please suggest any way by which I can clear/flush second level cache. Additionally where this second level cache is created on fileSystem ?

          Reply
          • Use any of
            sf.getCache().evictEntityRegions()
            sf.getCache().evictCollectionRegions()
            sf.getCache().evictDefaultQueryRegion()
            sf.getCache().evictQueryRegions()

  11. Thanks Lokesh for sharing it.

    You mentioned first level cache is available by default. What about second level cache. Do we need to have some configuration for the 2nd level cache.
    If yes, how we do it? Can you please elaborate?

    Reply
    • Hibernate uses first level cache mainly to reduce the number of SQL queries it needs to generate within a given transaction. For example, if an object is modified several times within the same transaction, Hibernate will generate only one SQL UPDATE statement at the end of the transaction, containing all the modifications.

      Reply
  12. Hi Loken,

    Your tutorials are really useful for understanding each concept very clearly. In one of the interview they asked me how to refresh web page content that database changes every 30 minutes automatically using any caching? if possible could you please explain me with examples?

    Reply
  13. Hey Lokesh,
    thanx for the early reply….Can u suugest me one: I am implementing rest Webservices, Now i need to implement Caching for the same, I have gone through so many Articles in the net regarding the Http etcc, but i am not able to cache my rest WS, can u put some light on the same…….

    Reply
  14. Hi Lokesh…..
    I have a doubt:
    My scenario: i am implementing hibernate second level caching:
    I have totally different application to alter the Database, i never use my HIbernate application for insert or update, i just use for Retrieving the data. suppose i have retrieved a data and i alter the database with different application, can u tell me whether the second level cache still works for the same database which i have altered using diff application…..

    Reply
    • Hibernate second level cache works at “SessionFactory scope/level”. So, till the time you have common SessionFactory for different sessions in your application you are good. But, in your case you have a completely different application with (assuming) different SessionFactory altogether, So in your case, second level cache WILL NOT WORK with exact behavior as in single application.

      Please do not misunderstood me here. Although the caching will happen at both applications but it will be independent at both ends regardless the changes done by any of application.

      Reply
  15. Hi Lokesh Gupta, Nice tutorials your posted i Have Implemented Second level Cache Mechanism.session is not loaded from the Second level cache if your remove the department.getName() its not hitting Second level Cache Mechanism could you tel me what is reason

    Reply
  16. Can u please explain about concurrency strategies used to configure second level cache at class level like transactional, read-write etc . i mean which strategy to be used when?

    Reply
  17. HI Lokesh
    I followed your step to print out below two lines
    System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());
    System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());

    above four conditions you mentioned, it always shows 0 0
    could you help me to figure it out?

    Thank you

    Reply
      • Hi, Lokesh,
        Thank you for replying
        I put those settings in xml file,
        a,b works well, but c shows 2 0 not 1 1
        do you know why it is ?
        Thank you

        Reply
        • It must me 0 2…………. not 2 0.
          Reason is second level cache is already created. So DB hits are 0. Delete the second level cache from file system and you will get desired result.

          Reply
          • Hi Lokesh,
            Can you specify where this second level cache is created on file system ? and Is there any way to clear/flush this cache ?

          • Use the configuration like this:

            <ehcache>
            <diskStore path=”java.io.tmpdir”/>
            <defaultCache
            maxEntriesLocalHeap=”10000″
            eternal=”false”
            timeToIdleSeconds=”120″
            timeToLiveSeconds=”120″
            maxEntriesLocalDisk=”10000000″
            diskExpiryThreadIntervalSeconds=”120″
            memoryStoreEvictionPolicy=”LRU”
            <persistence strategy=”localTempSwap”/>
            />
            </ehcache>

            Read this section from official documentation: http://www.ehcache.org/documentation/2.8/get-started/storage-options.html

  18. Thanks for your very nice post.

    Could you answer some questions from me?
    Can I disable the 2nd cache level? I know the advantages of caching mechanism but I think there are some disadvantages of it, so could tell me more about this?

    Thank you a lot, I’m waiting for your response.

    Reply
    • 1) Want to disable second level cache? Don’t configure it. Simple and most obvious.
      2) Yes, caching is boon to your application but it introduces certain overhead also. Everytime, you update something or delete something or even create create something, you need to invalidate certain cache blocks and re-build them so they have latest data. This step becomes more complex when cache is distributed. But believe me, advantages outweigh any such overhead.

      Reply
  19. Is cache applicable for only load methods or it is also for save/update methods.
    Mean when we save an entity will it be stored in cache before saving in DB ?

    Reply
    • NO. “Cache is only for selecting the data”. When you update something, if method return the updated entity, then in back-end it automatically fires a SELECT query which invalidate/update the first/second level caches. Otherwise if its only update operation, you will have to fetch the updated entity once again.

      Reply
  20. Hi Gupta, Nice tutorials your posted. I want Second Level Cache Implementation by using Hiberante4 with Maven. I tried many ways. There is proper resource to implement. Please Can you provide one example by using Hibernate4.

    Reply
  21. Ih,
    If i would like to use NO-SQL DB as hibernate second level cache, what i have to do..?
    what are the classes i need to customise.

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and related technologies, the best practices, algorithms, and interview questions.