Overcoming pitfalls with Query cache in Hibernate
Query caching in Hibernate used to cache query state and results, has multiple shortcomings if, not used judiciously. Some of the common pitfalls include:
(i) Query Cache structural representation is a QueryKey mapped to Object[][] (2-dimensional) and holds majority of persistent object references. QueryKey represents query specific data such as the SQL Query text with parameters (positional/named). QueryKey representation would get deteriorated if parameters represent entity object or a deep rooted object hierarchy.
(ii) If multiple equivalents of load() is invoked, there could potentially create multiple parameter versions of QueryKey containing equivalent duplicate entity objects exist in the cache.
Following are the patterns and practices that could be followed to fix these shortcomings:
1) Decorate org.hibernate.cache.StandardQueryCache and override the put() method to check if a canonical equivalent of a query results object already exist in the Object[][], and assign the same QueryKey if it exists. One needs to implement org.hibernate.cache.QueryCacheFactory also to plug into the Hibernate config.
2) Refactor the code to set entity’s keys as query parameters, rather than setting the entire entity object. Critreia representations should also use identifiers as parameters.
3) Write HQL queries to use identifiers in any substitutable parameters such as WHERE clause, IN clause etc.
4) Use positional parameters over named parameters as it could prevent using string pools.
5) If you are in a single JVM using in memory cache only, use hibernate.cache.use_structured_entries=false in your hibernate configuration.