Alois Reitbauer About the Author

Understanding Caching in Hibernate – Part Two : The Query Cache

In the last post I wrote on caching in Hibernate in general as well as on the behavior of the session cache. In this post we will have a closer look at the QueryCache. I will not explain the query cache in details as there are very good articles like Hibernate: Truly Understanding the Second-Level and Query Caches.

As we have seen in the last post the session cache can help in caching values when we have an _EntityKey_ available. If we do not have the key, we ran into the problems of having to issue multiple queries for retrieving the same object. This was the reason why the session cache worked fine for the _load_ method but not when we used _session.createQuery()_.

Now this is the point where the query cache comes into play.  The query cache is responsible for caching the results of queries – or to be more precise the keys of the objects returned by queries.  Let us have a look how Hibernate uses the query cache to retrieve objects. In order to make use of the query cache we have to modify the person loading example as follows.

 Session session = getSessionFactory().openSession();
 Transaction tx = session.beginTransaction();
 Query query = session.createQuery("from Person p where p.id=1");
 query.setCacheable(true);
 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");
 query.setCacheable(true);
 it = query.list().iterator();
 while (it.hasNext ()){
    Person p = (Person) it.next();
    System.out.println(p.getFirstName());
 }
 tx.commit();
 session.close();

As highlighted in bold face we had to add a line for defining that the query is actually cachable. If we would not do this, it won’t be cached.  (Note: The while loops could be omitted here. I am using for other examples where we have multiple results. …. just for code esthetics lovers). Additionally we also have to change the hibernate configuration to enable the query cache. This is done by adding the following line to the Hibernate configuration.

 <property name="hibernate.cache.use_query_cache">true</property>

Unlike most examples I found on the web I will not immediately enable the second-level cache. As the basic working do not depend on it and I do not want to create the impression that the query cache requires the second level or vice versa. Let us now verify that everything is working correctly. As we can see below only the first _query.list()_ result in a SQL statement to be issued.

Caching by the Query Cache For Two Susequent Queries

Caching by the Query Cache For Two Susequent Queries

The question now is, what happens internally. Therefore we analyze what happens within the second _get_ method of the _StandardQueryCache_. As we can see in the image below Hibernate first tries to retrieve the key values from the cache (as we can see the query cache internally uses the _EhCache_). After retrieving the keys the person entity is loaded from the session cache.

Internal Behavior of the Hibernate Query Cache

Internal Behavior of the Hibernate Query Cache

Query Cache Pitfalls

The query cache can be really usefull to optimize the performance of your data access layer. However there are a number of pitfalls as well.  This blog post describes a serious problem regarding memory consumption of the Hibernate query cache when using objects as parameters.

Conclusion

We have learned that the query cache helps us to cache the keys of results of Hibernate queries. These keys are then used to retrieve data objects using the Hibernate Internal loading behavior which involves the session cache and potentially also the second-level cache.

Comments

  1. Hi,
    I am using hibernate entity manager.
    I wanted to use the query cache as you explained above, but Query returned by entity manager createQuery() method does not support setCacheable() ability.

  2. Interessante Informationen.

  3. Gute Arbeit hier! Gute Inhalte.

  4. @Michael, what you can do is on the query you create, you can say:

    entityManager.createQuery(“select person from person”).setHint(“org.hibernate.cacheable”, true).getResultList();

    Then it will enable the query caching.
    Hope this helps.

  5. Alois Reitbauer Alois Reitbauer says:

    The point is that the Entity Manager is part of JPA and JPA does not define those nice caching methods. However as Shervin wrote you can use the hints methods to pass this on to hibernate.

    Caching is a bit of a neglected part of JPA – also of JPA 2.0 as it seems right now.

  6. Great post thank you. But I have a question; I can’t remove the cached query from the cache! I need to refresh the cache after performing data changes.

  7. When object actually gets into second level cache ?

  8. @Sami You can say explicitly that you do not want a query to be cached. However if you expect your data to change regularly query caching might not be the best ideal

  9. @Jigar. Objects get into the second level cache if you have defined that they should be cached. You can do this either by annotations or in a Hibernate config file.

  10. Hi sir,

    How would you caching of a particular named query?

  11. Sorry a mistake in the above post.

    How would you remove the caching of a particular named query?

  12. Thanks a lot for your clear explanation but where can i see this figure parts..How to see what has got executed?(blue highlighted parts I mean)

  13. @Bavani

    You have to explictly specify that a query gets cached so it will not be cached by default. Is this what you meant?

  14. @Hema
    The traces show what has been executed. You can see this for your code by using tracing solutions like dynaTrace.

  15. @Alois tnx for the tip: use of dynaTrace.
    but, I couldn’t even silence myself for what I notice about your contraditory (paradoxal) statements: “…enable the second-level cache. As the basic working do not depend on it and I do not want to create the impression that the query cache requires the second level or vice versa.” and “as we can see the query cache internally uses the _EhCache_”.
    For instance, is there the dependence ehcache.jar and is it referenced in your ExampleApp config??!
    Finally, QueryCache really demands (or not) a 2ºlevel Cache Provider??!

    Derlon

  16. @Alois tnx for the tip: use of dynaTrace.
    But, I couldn’t even silence myself for what I notice about your contraditory (paradoxal) statements: “…enable the second-level cache. As the basic working do not depend on it and I do not want to create the impression that the query cache requires the second level or vice versa.” and “as we can see the query cache internally uses the _EhCache_”.
    For instance, is there the dependence ehcache.jar and is it referenced in your ExampleApp config??!
    Finally, QueryCache really demands (or not) a 2ºlevel Cache Provider??!

    Derlon

  17. Derlon,

    I state that you can use the query cache also without the second level cache. In many cases you will want to however use both, but you do not need to.

    EhCache is just one implementation of a cache provider to be used with Hibernate. In Hibernate – as I stated- EhCache is also used for the query cache. This however does not mean you use the second level. This depends on whether you set your Hibernate properties to enable the cache

  18. I am applying EHCache for Hibernate4,
    This is my configuration
    In entity,i configured like this

    @Table(name = “tbl_lookup”)
    @Cache(usage=CacheConcurrencyStrategy.READ_ONLY)

    In hibernate.cfg.xml :
    org.hibernate.cache.EhCacheProvider
    true
    true
    org.hibernate.cache.ehcache.EhCacheRegionFactory

    Ehcache.xml :

    </ehcache?
    I have add the jars : ehcache-core-2.4.5.jar,hibernate-ehcache-4.1.0.Final

    Prob : For first click it getting the objects putting into 2nd level cache(ex:SecondLevelCachePutCount -30),from next click onwards it is getting the 7 objects which are there in second level cache.now it is updating SecondLeveCacheMissCount,SecondLevelHitCount(if we observe with JConsole).It should not go to DB again.

    Please Help me…..
    Thanks in advance.

Trackbacks

  1. [...] 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 Documentation provides a good [...]

  2. [...]                                                             Part 2 – http://blog.dynatrace.com/2009/02/16/understanding-caching-in-hibernate-part-two-the-query-cache/ [...]

  3. [...] Queries, however, are not cached by default. If you want to know more read this article on the Hibernate Query Cache. public void doubleLoad (){ EntityManager em = factory.createEntityManager(); [...]

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

  5. [...] 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 Documentation provides a good [...]

Comments

*


nine − = 4