Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Second level query caching issue with same where clause

My application uses JPA (1.2), Spring (3.1.2), Spring Data (1.1.0) and Hibernate (4.1.7). DataBase : Oracle10g

We have enable second level caching. It's working fine with entity but it's creating issues on named query caching.

The issue is: If named query has same where clause but different select statement, then whatever the first query execute it's giving the same result for the second query also.

Like my first query(countRelease) is

select count(r) from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL)
order by r.validityStart

and second query(findRelease)is

select r from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL)   
order by r.validityStart

If first query is run first then count will come and after that if I run second query then also count will come it should give me the list of release entity.

If I remove query cache it's working fine and if I make some changes in second query where clause then also it's working fine but I dont need to do that.

How we can solve this issue?

My Java code

@Query(name="findRelease")
@QueryHints({@QueryHint(name = "org.hibernate.cacheRegion", value ="cvodrelease"),@QueryHint(name = "org.hibernate.cacheable", value ="true") })
public List<Release> findRelease();

@Query(name="countRelease")
@QueryHints({@QueryHint(name = "org.hibernate.cacheRegion", value ="cvodrelease"),@QueryHint(name = "org.hibernate.cacheable", value ="true") })
public Long  countOfRelease(Date today);

Cache Configuration

<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" /> 
<property name="hibernate.cache.provider_configuration_file_resource_path" value="ehcache.xml" />

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"  p:cacheManager-ref="ehcache"/>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml"  p:shared="true"/> 
like image 743
Ranu Jain Avatar asked Feb 18 '13 11:02

Ranu Jain


People also ask

What are the hibernate second-level and query caches?

This post will go through how to setup the Hibernate Second-Level and Query caches, how they work and what are their most common pitfalls. The Hibernate second level cache is an application level cache for storing entity data. The query cache is a separate cache that stores query results only.

How does the second level cache work in SQL Server?

If a query under execution has previously cached results, then no SQL statement is sent to the database. Instead the query results are retrieved from the query cache, and then the cached entity identifiers are used to access the second level cache. If the second level cache contains data for a given Id, it re-hydrates the entity and returns it.

What happens if hibernate cache is not defined?

If expiration and eviction policies are not defined, the cache could grow indefinitely and eventually consume all of available memory. In most cases, Hibernate leaves cache management duties like these to cache providers, as they are indeed specific to each cache implementation.

What is the hibernate Cache region name?

For each entity class, Hibernate will use a separate cache region to store state of instances for that class. The region name is the fully qualified class name. For example, Foo instances are stored in a cache named com.baeldung.hibernate.cache.model.Foo in Ehcache.


1 Answers

JPA 1.0 standard had no caching included (and JPA 1.2 doesn't exist).

JPA 2.0 standard introduced caching - including the Shared Cache (a "first level cache" for each EntityManagerFactory instance) and the Application cache (second level cache for ALL EntityManagerFactor instances). Also each PersistenceContext for each EntityManager instance acts as its own lowest level cache - the "zero level cache".

What this means is that your behaviour is all specific to Hibernate 4.1.7 and has nothing to do with any standard or any other product.

Caching is not used when the the data cache does not have any cached data for an id in a query result.

That's a direct quote from Apache OpenJPA docs, not Hibernate or JPA spec. You can ignore, but seems it would be true for Hibernate.

Queries that result in projections of custom field types or BigDecimal or BigInteger fields are not cached.

That's a direct quote from Oracle Kodo JPA docs, not Hibernate or JPA spec. Might be wise to ignore this.

The query cache does not cache the state of the actual entities in the cache. It caches identifier values and results of value type. Therefore, always use the query cache in conjunction with the second-level cache for those entities which should be cached as part of a query result cache. .

That's a direct quote from Hibernate 4.1 docs. So you can follow this advice - as long as you take it in context: it's saying to include the second-level cache if you want to cache entities returned from queries. If you don't want to cache entire entity objects, but just want to cache the results of NamedQueries containing primitive data types (projections), then the first level cache is all you need.

My suggestion:

  1. I think the problem might be that COUNT(r) returns a BigInteger to java, which cannot be cast to Object for caching. You can call addScalar("count", Hibernate.LONG) on the query to tell hibernate to use a different type - LONG. See blog.pfa-labs.com/2009/12/caching-raw-sql-count-with-hibernate.html plus Is/Can Hibernate's Second-Level Cache be Used for COUNT() operations?

  2. The query cache should be able to handle this. The second level cache should only be needed for entity objects.

  3. Be very careful you understand the read/write behaviour of the objects you are trying to cache - and ensure the number of reads is much greater than the number of writes. Otherwise caching could give no benefit or even slow things down and cause data inconsistencies.

  4. Be aware that some JDBC drivers also cache data - if yours is it will affect JPA results and JPA won't even know about it.

From Mike Keith's "Pro JPA 2": Most [JDBC] drivers cache connections and statements. Some caches also keep track of table or column state that is essentially transparent to the JPA provider, but that nonetheless can offer some savings in terms of not having to go to the database to get data on every call. This is generally feasible in the driver only if it is known that either the data is read-only or the driver controls database access exclusively.

JDBC caching, if available, should be controllable via configuration settings specific to the driver.

EDIT:

In the first query, "order by r.validityStart" does nothing - you could remove it, and all will work.

like image 130
Glen Best Avatar answered Sep 24 '22 16:09

Glen Best