This post explains how to manage hibernate second level cache. It is a comprehensive step by step guide which explains how to enable monitor and disable hibernate cache.
Some hard facts
1. By default hibernate uses second level cache when the entity is fetched by Id – that means all findbyX in your DAOs where X is anything other than primary key will not use cache.
2. Associations are not cached by default – that means if you have an association in your entity then database will be queried every time for fetching the association
3. Queries are cached only when Criteria.setCachable(true) or Query.setCachable(true) is explicitly set.
So here is your, Guide to enable hibernate caching
(assuming you are using annotations, for hbm files, use the configurations corresponding to these annotations)
1. Annotate "to be cached" entities with @Cache
2. Make sure that "to be cached" associations are annotated with @Cache
Example:
@Cascade(org.hibernate.annotations.CascadeType.DELETE)
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<Template> templates;
3. For Criteria's set Cachable as true;
Example:
public List<Template> findByWeightage(List<Long> weightages) {
Criteria crit = getSession().createCriteria(Template.class);
crit.add(Restrictions.in("weigtage", weightages));
crit.setCacheable(true);
return (List<Template>) crit.list();
}
4. For Qeuries set Cachable as true
Example:
SQLQuery query = getSession().createSQLQuery(“.......”);
query.setCacheable(true);
List list = query.list();
5. Mark your named queries as cachable by adding a hint
hints = { @QueryHint(name = "org.hibernate.cacheable", value = "true") }
6. In your dialect properties add
<prop key="hibernate.cache.use_query_cache">true</prop> <!--For query cache-->
<prop key="hibernate.cache.default_cache_concurrency_strategy">read-only</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!--following two entries for ehcache-->
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
<prop key="net.sf.ehcache.configurationResourceName">ehcache.xml</prop>
7. Let spring manage the transactions, remove any transaction related configurations from dialect properties (be careful, if you disable the following configurations then you may need to adjust your spring transaction configurations )
<!--prop key="hibernate.current_session_context_class"> thread </prop-->
<!--prop key="hibernate.transaction.auto_close_session">true</prop-->
<!--prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop-->
How to verify the caching?
1. enable JMX in your application. For remote tomcat, add the following catalina options
CATALINA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8089 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
2. run jconsole with the required jars in your class-path
jconsole -J-Djava.security.manager
-J-Djava.security.policy==server.policy
-J-Djava.class.path=/usr/lib/jvm/java-6-oracle/lib/jconsole.jar:/usr/lib/jvm/java-6-oracle/lib/tools.jar:/home/santhosh/trunk/commons/app/WEB-INF/lib/hibernate-core-3.6.0.Final.jar
3. If java security does not allow de-serializing the classes configure server.policy in class-path. Sample content given below
grant codebase "file:/home/santhosh/trunk/commons/app/target/app/WEB-INF/lib/hibernate-core-3.6.0.Final.jar"
{
permission java.security.AllPermission;
};
grant codebase "file:/usr/lib/jvm/java-6-oracle/lib/jconsole.jar"
{
permission java.security.AllPermission;
};
grant codebase "file:/usr/lib/jvm/java-6-oracle/lib/tools.jar"
{
permission java.security.AllPermission;
};
4. Enable hibernate statistics by adding the following in dialect propertis
<prop key="hibernate.generate_statistics">true</prop>
5. Now you will be able to see the statistics using the Hibernate bean in jconsole
What if you want to disable the cache?
If you are going to comment the following three lines
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!--following two entries for ehcache-->
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
Then you are going to get this
Invocation of init method failed; nested exception is org.hibernate.cache.NoCachingE
Solution is to set
<prop key="hibernate.cache.use_ query_cache">false</prop>
<prop key="hibernate.cache.use_ second_level_cache">false</ prop>
<prop key="hibernate.cache.use_
Other Possible Exceptions and solutions
java.lang.ClassCastException: java.math.BigInteger cannot be cast to [Ljava.lang.Object;
at org.hibernate.cache. StandardQueryCache.put( StandardQueryCache.java:106)
To fix this add scalar to your query
query.addScalar("employee.id", StandardBasicTypes.BIG_INTEGER);
Note: Spring version 3.2 and Hibernate version 3.6