< Go Back to Homepage

Understanding Caching in Hibernate – Part One : The Session Cache

by Alois Reitbauer, Feb 16, 09

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.

Share
  • Print
  • Facebook
  • Digg
  • del.icio.us
  • StumbleUpon
  • Sphinn
  • Google Bookmarks
  • Mixx
  • LinkedIn
  • blogmarks
  • MisterWong
  • MSN Reporter
  • Technorati
  • Yahoo! Buzz
  • email

Related posts:

  1. Understanding Caching in Hibernate – Part Two : The Query Cache In the last post I wrote on caching in Hibernate...
  2. Understanding Caching in Hibernate – Part Three : The Second Level Cache In the last posts I already covered the session cache...
  3. Lazy vs. Eager Loading in Hibernate I recently gave a presentation at Jax 2008 where I...
  4. JPA Under The Hood – Understanding the Dynamics of Your JPA Framework I recently gave a talks on the behaviour of different...
  5. Selected readings for my JAX London Session Here you can find some selected material on performance related...

Trackback

17 comments yet

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

  2. navier s. @ 2009-02-17 22:23

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

  3. Alois Reitbauer @ 2009-02-18 09:32

    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

  4. [...] is very nice articles. I was suprized. part 1 < a [...]

  5. Benjamin @ 2009-02-24 09:26

    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.

  6. Alois Reitbauer @ 2009-02-24 21:03

    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.

  7. Good stuff ….
    thanks

  8. Thanks for this article…

  9. [...] 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 [...]

  10. 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.

  11. Very nice site!

  12. [...] 3. Understanding Caching in Hibernate, Part 1-3 [...]

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

  14. [...] The Session Cache [...]

Add your comment now