Alois Reitbauer About the Author

Understanding Caching in Hibernate – Part One : The Session Cache

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 download and evaluate dynaTrace.

Comments

  1. Very clear example. However, I’m still not clear why the first case with the query failed to find the cache in session?

  2. Alois Reitbauer Alois Reitbauer says:

    The cache retrieval failes as Hibernate here does not know that the object is already cached as it cannot relate the query to the Entity Key. How this is does is shown in the post on the query cache

  3. Good introduction. But you should name the Problems with First Level Cache in batch-jobs.
    Hibernate is not intended for batch-jobs, but often used because it seems very simple ;)
    Without periodical flush/clear (or disabling the first level cache via session.setCacheMode(CodeMode.IGNORE)) you would run into OutOfMemoryExeptions while inserting/updating large amounts of data.

  4. Alois Reitbauer Alois Reitbauer says:

    Benjamin,

    I totally agree :-) . I am using this as an anti patterns of O/R Mapper usage. Even the Hibernate documentation warns to not do that. :-) . Batch processing often can be much more easily done by a single clever SQL statement instead via O/R mappers which need a bunch of statements to do the same. Not because they are bad, but because – as you say – they have not been built for this use case.

  5. Good stuff ….
    thanks

  6. Thanks for this article…

  7. I disagree about batch insert with ORM.
    I can insert thousand of objects without any memory problem, even without flush.
    It depends on the the ORM you use and its implementation of L1 cache.
    Obviously, performances of rows insert in a single table are faster with plain JDBC.

  8. Very nice site!

  9. As far as i know you cannot disable the first level cache. You can bypass by using statelesssession for example, but you cannot disable this as you wrote:
    Benjamin : “or disabling the first level cache via session.setCacheMode(CodeMode.IGNORE)”

    This flag is used against the second level cache:
    http://ajava.org/online/hibernate3api/org/hibernate/Session.html#setCacheMode(org.hibernate.CacheMode)

  10. First use case find by query will be executed in one query if the second level is enabled.
    First level cache is object cache(Object equal comparison). second level cache is cache in serialise format(text format) so it is able to find by using query.

  11. The cache retrieval failes as Hibernate here does not know that the object is already cached as it cannot relate the query to the Entity Key..I can insert thousand of objects without any memory problem, even without flush.
    It depends on the the ORM you use and its implementation of L1 cache.

  12. The cache retrieval is a failure as Hibernate here does not know that already the object is cached as it cannot relate the query to the Entity Key.It depends on the the ORM you use and its implementation of L1 cache.

  13. I didn’t know about those cache types, good thing I read this article. Great examples, thanks a lot!

  14. Very interesting, especially the 3 caching types. As I understood, I could reduce server load by reducing database access. I will speak with my webmaster about your post. Thank you very much!

  15. thanks for this article, explains the session caching really well!

  16. gud

  17. Good looking website. I really like what your blog has to say about the performance of cache and how it can speed up your website.

  18. Nice work on putting together a very interesting post. Fabulous ideas and very helpful information. Well thought out and well written.

  19. This is one of the great blog post. I like your writing style. I appreciate your efforts. Keep posting some more interesting blog posts.

  20. This is probably the best Session Cache manual I have ever seen online. Great work guys!

    Mike

  21. Thanks this clarifies some of my questions. The Session Cache manual is quite useful for my project

  22. Hi, I’m facing a problem with reloading an object.

    The scenario is
    a) storing an object with status ‘R’
    b) calling a stored procedure, which changes the status to ‘S’ in db
    c) fetching the updated status. Instead of giving ‘S’, still the status is showing as ‘R’

    Hibernate cache configuration is
    true
    org.hibernate.cache.EhCacheProvider

    any idea what could be the problem here?

  23. I was wondering why my website is so slow. One day I read that it has to do with caching. But I am not that much into computer stuff; anyways I had to look it up. After some time I stumbled upon your post and it helped me to understand a few thing. Also I showed it to some friend who`s a little bit more into computer stuff than I am. He then helped me out with the caching of my website. He said that all I need was some wp plugin. But the plugin didn`t work. But thanks to your post he and I managed to get the caching issue fixed :-)

  24. Very interesting and informative blog. Hope we get some updates

  25. I really enjoyed your blog as well. You provided some very interesting information and I will definitely check back to read other entries you include on your blog.

  26. That’s very interesting for me. I also have enjoyed reading the stuff here.

  27. Which is worth it to read personally. Furthermore include experienced examining any things at this point.

  28. very helpful info…I was pulling my hair out… you gave me the clue what I was missing…Thanks!!!

    Dan

  29. I really don.t understand the caching feature.Thanks for sharing the important sharing about caching.I have to say this is totally open a new secret in front of me.

  30. I appreciate your efforts to make a good discussion here on this topic. It brings possibilities to find and move with some new ideas.

    All the best

  31. Thanks Alois,

    had to read it three times to think I really got it…thanks for the video, was very helpful

    Peter

  32. This is awesome work throughout.No one can ignore the hard work require to create such kind of stuff.Thanks for the informative sharing and hope many more are yet to come.

  33. The build in cache in NHibernate is stand alone and in process in nature which means it can perform well but it has some limitations as well. When you are dealing with huge amount of data and there are many number of servers, then you have to go for a Secondary level cache which can perform well under these circumstances.

    NCache is one distributed cache provider which offer its plug in for NHibernate level two cache. I’ve used it during one of my projects and I was very happy with its results. Have a look from here,

    http://www.alachisoft.com/ncache/nhibernate-l2cache-index.html

  34. The hibernate option is available on most computers running Microsoft Windows, but depending on your settings and installed updates, you may find the option disappearing from your shutdown menu. Thanks.
    Regards,
    http://www.courseworkhelp.org/

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

Trackbacks

  1. [...] Performance, Scalabilty and Architecture – Java and .NET b…/b [...]

  2. [...] the last posts I already covered the session cache as well as the query cache. In this post I will focus on the second-level cache. The Hibernate [...]

  3. [...] Caching in Hibernate: Part I – The Session Cache, Part II – The Query Cache, Part III – The Second Level [...]

  4. [...] Reads: Understanding Hibernate Session Cache, Understanding the Query Cache, Understanding the Second Level [...]

  5. [...] Reads: Understanding Hibernate Session Cache, Understanding the Query Cache, Understanding the Second Level [...]

  6. [...] the last post I wrote on caching in Hibernate in general as well as on the behavior of the session cache. In this [...]

  7. [...] Reads: Understanding Hibernate Session Cache, Understanding the Query Cache, Understanding the Second Level [...]

  8. [...] 延伸阅读:Understanding Hibernate Session Cache、Understanding the Query Cache、Understanding the Second Level Cache [...]

  9. JavaPins says:

    Understanding Caching in Hibernate – Part One : The Session Cache about:performance…

    Thank you for submitting this cool story – Trackback from JavaPins…

Comments

*


9 − nine =