Guide to Hibernate First Level Cache

Caching is a 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. Hibernate achieves the second goal by implementing the first-level cache.

1. Available Only through Session Object

First level cache in hibernate is enabled by default and we do not need to do anything to get this functionality working. In fact, we can not disable it even forcefully.

It is easy to understand the first level cache if we understand the fact that it is associated with Session object. As we know the Session object is created on-demand from SessionFactory and it is lost, once the current session is closed. Similarly, the first-level cache associated with the Session object is available only till the session object is live.

The first-level cache is available to Session object only and is not accessible to any other session object in any other part of the application.

Hibernate first level cache

2. Facts About First-Level Cache

  1. The first-level cache is associated with a specific “session” object and other session objects in the application can not see it.
  2. The scope of cache objects is of the session. Once the session is closed, cached objects are gone forever.
  3. The first-level cache is enabled by default and we can not disable it.
  4. When we query an entity the first time, it is retrieved from the database and stored in the first-level cache associated with hibernate session.
  5. If we query the same entity again with the same session object, it will be loaded from the cache and no SQL query will be executed.
  6. The loaded entity can be removed from the session using evict() method. The next loading of this entity will again make a database call if it has been removed using evict() method.
  7. The whole session cache can be removed using clear() method. It will remove all the entities stored in the cache.

Let us verify the above facts using examples.

3. Demo

3.1. Retrieve Entity in Same Session

In this example, I am retrieving DepartmentEntity from the database using a hibernate session. I will retrieve the entity multiple times and will observe the SQL logs to see the differences.

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

//fetch the department entity from database 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());

session.getTransaction().commit();
HibernateUtil.shutdown();
Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

As you can see the second “session.load()” statement does not execute SELECT query again and loads the department entity directly from the cache.

3.2. Retrieve Entity in Different Session

With a new Session, the entity is fetched from the database again irrespective of whether it is already present in any other Session in the application.

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

Session sessionTemp = HibernateUtil.getSessionFactory().openSession();
sessionTemp.beginTransaction();
try
{
	//fetch the department entity from database 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());

	department = (DepartmentEntity) sessionTemp.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());
}
finally
{
	session.getTransaction().commit();
	HibernateUtil.shutdown();

	sessionTemp.getTransaction().commit();
	HibernateUtil.shutdown();
}
Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource

We can see that even if the department entity was stored in “session” object, still another database query was executed when we use another session object “sessionTemp”.

3.3. Removing Cached Entity from First-level Cache

Though we can not disable the first-level cache in hibernate, we can certainly remove some objects from it when needed. This is done using two methods :

  • evict(): removes a particular object from cache associated with the session
  • clear(): remove all cached objects associated with the session

So these methods are essentially like remove one and remove all.

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
try
{
	//fetch the department entity from database 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());

	session.evict(department);
	//session.clear(); 

	department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());
}
finally
{
	session.getTransaction().commit();
	HibernateUtil.shutdown();
}
Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource

Happy Learning !!

Leave a Comment

  1. Hi ,
    What happened to the object stored in the first level cache if another session updated it in the Data Base?

    Reply
    • I have the same doubt. Will the cached object gets updated?
      Also can we use merge() method to update the cached object? If so why use evict() when we can use merge() ? Any replies would be truly appreciated

      Reply
      • If there is some direct DB update, session will not know it and no cache update will happen. Merge method will overwrite in the DB again. Based on whether you want to fetch latest data from database (refresh method) or overwrite database again with data stored in entity (merge method) – choose accordingly. Read more about Merging and Refreshing Entities.

        Reply
        • if you want to store only update fields you can provide “dynamic-update = true” in .hbm .xml file during configuration.

          So, if session load object update A field, it will only update a field.

          Reply
  2. I have few doubts regarding hibernate cache.

    1. Where the cached object is stored exactly? In which memory?

    2. Lets say I am loading an object first time using load method. It will be cached in session.
    Next time in the same session, I am trying to query same object with a hql query with some criteria. Will it be fetched from cache or database?

    Reply
  3. lokesh
    first
    user 1 execure query thru hibernate
    “select * from dept where id =40?”

    then again user 2 query thru hibernate

    “select * from dept where id =50?”

    how does hibenate figure out if it needs to go to cache or go to databsae?

    in this case obsivlosuly it needs to go to DB

    Reply
    • i mean
      user 1 execute query thru hibernate
      “select * from dept where id =40?”

      then again user 1 query thru hibernate

      “select * from dept where id =50?”

      Reply
  4. java.lang.ClassNotFoundException: org.hibernate.cache.EhCacheProvider
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    at java.lang.Class.forName0(Native Method)

    Reply
  5. Very brief and clear explanination, thanks for the artical.

    To dig the issue (intoduced by Kartthik) further ,

    How Transactions are managed to avoide updates on stale objects in hibernate.

    Reply
  6. HI Lokesh,

    I am using Hibernate second level cache. But I have some points

    1. for some entities i required cache should be created at the server startup. How I can achieve it with hibernate and ehcache.
    2. In the session.load method we required Primary key for searching. But User never know the primary key they only know the Unique key like some code of the entity. then how I will get it from session.

    I hope you understand my problem.

    Thanks.

    Reply
  7. very instructive, thank you so much.
    Now I’m going to read your explanation about second level.
    I’m having many problems in an clustered production enviroment, many heavy queries.

    Reply
  8. Hi Lokesh, Can you please explain. How Session cache is working internally. I am asking about internal implementation of this cache mechanism.

    Reply
    • In case of single session, your application code always update this cache object so it is always updated. Hibernate takes care of synchronizing the changes with database at time of flushing the session.

      Now consider another example:

      machine 1: reads the data and returns it for editing somewhere else
      machine 2: also reads the data for modification
      machine 1: updates the data and commits.
      machine 2: tries to do an update and commit.

      What will happen when the second machine tries to commit its changes? Hibernate will see that the data has changed while machine 2 was working on the data. That is, machine 2’s update is on stale data. Hibernate can’t always merge the two changes (nor is that always desired behaviour), so it rejects the second update by throwing org.hibernate.StaleObjectStateException.

      The simplest solution, perhaps, is to add a version field using @Version on your data objects. Hibernate will automatically maintain the “version” of the data. Whenever an update takes place, the version will be changed automatically by Hibernate. Your job is the check that the version hasn’t changed between when you read the data and when you update the data. If they don’t match, you can do something to handle the problem (i.e. tell the user). There are some more sophisticated techniques for preventing concurrent updates, but this is the simplest.

      Reply
  9. Thanks for your brief explanation on this.However I had a doubt on how this can be useful in real time scenario where I have 2 controllers and in each controller , it is hitting the database through opening the new session object,getting the results and immediately closing the session since it not possible to open the session until second controller results. So in those scenarios where it using the First Level Cache not hitting the database for second controller.

    Reply
    • How to use First Level cache if we need to hit the database for same data from more than one place in application. for example in application I have 10 pages, 1st page, I hit the database and while retrieving the results from database by default it stored it in cache with in that session.

      Again, I need to use same data in 5th page, how can I retrieve data from cache instead of database since it will open another session

      Reply
    • In My application, I have 10 pages and in 1st page I hit the database and retrieve the results directly from database and this time it used first level cache by default.

      Again I need to use same data in 5th page, how can I use from cache instead of database.

      Reply
  10. Thank you very much. WIth your explanation I being able to resolve my issue, but, I used SessionFactory.openStatelessSession() to get a “fresh” entity.

    Reply
  11. Hi Lokesh, I m stuck in 1 issue,
    i m goin to delete multiple object in dao like ..

    sf.getCurrentSession.delete(object1);
    sf.getCurrentSession.delete(object2);
    sf.getCurrentSession.delete(object3);

    And getting following exception :
    org.hibernate.nonuniqueobjectexception a different object with the same identifier

    Pls help in resolving the issue.

    Reply
    • Can you please share the code is possible. That will be much better. Without code it’s very hard to guess.

      Basically, what hibernate is saying is that you have two objects which have the same identifier (same primary key) but they are not the same object.

      Reply
  12. Example is good, but every where you copied same out put. If you use evict() 0r clear() it should display three select queries in output.

    Reply

Leave a Comment

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode