Archive

Posts Tagged ‘query-cache’

A Quick note about Hibernate Caching

September 14th, 2009 Shrihari No comments

1)    First Level Cache (Transaction Layer)

a) Associated with a Hibernate Session (transaction scoped) and this cache is used by Hibernate transparently. Hibernate requires a key to load object from the session cache. Hence its better to call a load() or get(), when the key(EntityKey) is known, rather than using a HQL query.
b) All queries (state of an entity, updates) in the cache gets flushed / committed to the database only when  Transaction context ends (i.e.) getTransaction().commit is called.
c) Always used and cannot be turned off.

2)    Second Level Cache (Application Layer)

a) Associated with a Hibernate’s SessionFactory (process scoped). Enabled by default in Hibernate 3 and uses EHCache as default cache provider.
b) The cache entries are dehydrated states of entity objects. A dehydrated state of entity refers to a key­-value  pair where key is the entity id (of the dehydrated entity) and the set of (deep copy) of attribute­values  (dehydrated entity fields) refer to the value.  Hibernate does not cache associations in a dehydrated object by default. One has to manually configured which association in a dehydratable entity to be cached.

Syntax : { id ­> { atribute1, attribute2, attribute3,{attribute41, attribute42},… } }

3)   Query cache (org.hibernate.cache.QueryCache)

a) Defines 2 cache regions : org.hibernate.cache.StandardQueryCache (stores query with parameters as cache key) and org.hibernate.cache.UpdateTimestampsCache (keeps stale query results of last results fetch). Both the cache regions are evicted when the entity related to the cacheable query is updated.

Syntax : { query,{parameters}} —> {id of cached entity}

b) A specific query results are cached, by specifying setCacheable(true) on Session’s Query handle.

1)    First Level Cache (Transaction Layer)

a) Associated with a Hibernate Session (transaction scoped) and this cache is used by Hibernate transparently. Hibernate requires a key to load object from the session cache. Hence its better to call a load() or get(), when the key(EntityKey) is known, rather than using a HQL query.

b) All queries (state of an entity, updates) in the cache gets flushed / committed to the database only when  Transaction context ends (i.e.) getTransaction().commit is called.

c) Always used and cannot be turned off.

2)    Second Level Cache (Application Layer)

a) Associated with a Hibernate’s SessionFactory (process scoped). Enabled by default in Hibernate 3 and uses EHCache as default cache provider.

b) The cache entries are dehydrated states of entity objects. A dehydrated state of entity refers to a key­-value  pair where key is the entity id (of the dehydrated entity) and the set of (deep copy) of attribute­values  (dehydrated entity fields) refer to the value.  Hibernate does not cache associations in a dehydrated object by default. One has to manually configured which association in a dehydratable entity to be cached.

Syntax : { id ­> { atribute1, attribute2, attribute3,{attribute41, attribute42},… } }

3)   Query cache (org.hibernate.cache.QueryCache)

a) Defines 2 cache regions : org.hibernate.cache.StandardQueryCache (stores query with parameters as cache key) and org.hibernate.cache.UpdateTimestampsCache (keeps stale query results of last results fetch). Both the cache regions are evicted when the entity related to the cacheable query is updated.

Syntax : { query,{parameters}} —> {id of cached entity}

b) A specific query results are cached, by specifying setCacheable(true) on session’s Query handle.

Overcoming pitfalls with Query cache in Hibernate

June 27th, 2009 Shrihari No comments

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.

Categories: Uncategorized Tags: ,