Alois Reitbauer About the Author

Understanding Caching in Hibernate – Part One : The Session Cache

Update Jan 21, 2016: You can now test all this on your own application FOR FREE – FOR LIFE. Get your Dynatrace Personal License and Watch our YouTube Tutorials

Hibernate offers caching functionality which is designed to reduces the amount of necessary database access.  This is a very powerful feature if used correctly. However I have seen a lot of cases and also talked to many people on caching in Hibernate, where caching is either not understood correctly or even used the wrong way.

There are already a number of good articles on Hibernate caching, which provide good hints on how to use the cache. The Hibernate documentation itself offers good advise. Still I see value in having a deeper look at the dynamic and behaviour of the Hibernate cache as it might help people to understand it even better.

Hibernate Cache Types

Hibernate uses different types of caches. Each type of cache is used for different purposes. Let us first have a look at this cache types.

  • The first cache type is the session cache. The session cache caches object within the current session.
  • The second cache type is the query Cache. The query cache is responsible for caching queries and their results.
  • The third cache type is the second level cache. The second level cache is responsible for caching objects across sessions.

Now as we have an overview of caching types we can look at them in more detail. We will use dynaTrace to provide detailed insight into the dynamic of Hibernate caching. In this post we will start looking closer at the session cache.

Sample Data Model

For the samples used in the post, we will use a very simple data model. Although it is simple it is sufficient for illustration purposes and you should not have any problems mapping it to your application’s use cases.

Our data model consists of two entities – Persons and Addresses. Persons have references to Addresses. This allows us to explore caching behaviour regarding single entities as well as relations.

The Session Cache

As already the session cache caches values within the current session.  This cache is enabled by default.  Let us have a look at the following code sample. We create two queries to load a person object from cache. As we are loading the same object twice, we expect it to be retrieved from the cache.

 Session session = getSessionFactory().openSession();
 Transaction tx = session.beginTransaction();
 Query query = session.createQuery("from Person p where p.id=1");
 Iterator it = query.list().iterator();
 while (it.hasNext ()){
   Person p = (Person) it.next();
   System.out.println(p.getFirstName());
 }
 query = session.createQuery("from Person p where p.id=1");
 it = query.list().iterator();
 while (it.hasNext ()){
   Person p = (Person) it.next();
   System.out.println(p.getFirstName());
 }       
 tx.commit();
 session.close();

Using the code above we would expect the query to be executed only once. However if we look at the PurePath of this transaction we can see, that two database queries have been executed.

Loading a person two times in a row, but no session cache involved

Loading a person two times in a row, but no session cache involved

Now we will not use the createQuery but instead the load Method and pass the key directly as shown in the code below. The System.out.println calls by the way are required to force Hibernate to load data at all. If we would not put them in, nothing would get loaded. This is because data is always by default loaded lazyly in Hibernate. Thoug interesting this if off topic for this post.

  Session session = getSessionFactory().openSession();
  Transaction tx = session.beginTransaction();
  Person person1 = (Person) session.load(Person.class, 1L);
  System.out.println(person1.getFirstName());
  Person person2 = (Person) session.load(Person.class, 1L);   
  System.out.println(person2.getFirstName());       
  tx.commit();
  session.close();

As we can see in the trace below, now only one database query is issued. The same behaviour could have been achieve by using get instead of load.  For more information on the difference between these two methos either refer to the Hibernate documentation or read this nice blog post(I have chosen one from may out there)

Loading by class and key using session cache

Loading by class and key using session cache

The question now is what is the difference between these two scenarios and why does it work in one case and not in the other. Therefore we have to look deeper into Hibernate to see what is going on the second example. As shown below Hibernate first tries to retrieve the object within the session, if this fails (like in the green section), the object will be loaded from the database.  The objects retrieval and storage in handled by the  _PersistenceContext_ object, which is kept by within the Hibernate session.

Difference First and Second Time Loading

Difference First and Second Time Loading

The handling for storing objects in the persistence context is the same, whether we use the _load_ method or a hibernate query. The figure below shows the dynamic behavior for loading the object via a hibernate query. This however also means that all objects loaded within a session are kept as long this session is open. This can lead to performance problems due to memory consumption in cases where a large amount of objects are loaded.

Persistence Context Behavior When Using Hibernate Query

Persistence Context Behavior When Using Hibernate Query

Conclusion

Hibernate internally always uses the session cache transparently.  We have also seen that Hibernate requires a key to load object from the session cache. So in case we have a key available it is prefered to use load and a key instead of a HQL query.

If you’re interested in getting a better idea of how Dynatrace provides this transactional context (PurePath), you can get your own Dynatrace Personal License.

About The Author
Alois Reitbauer
Alois Reitbauer

Comments

  1. Nice article. I have to thacnk you for your article.

  2. Thank you for the article.

Speak Your Mind

*

Do the math so we know you are human *