Question

in my applicationcontext.xml

<bean id="annotatedsessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="packagesToScan" value="testonly.package.model" />
<property name="hibernateProperties">
    <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.format_sql">true</prop>
        <prop key="hibernate.use_sql_comments">true</prop>
        <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
        <prop key="hibernate.c3p0.min_size">5</prop>
        <prop key="hibernate.c3p0.max_size">20</prop>
        <prop key="hibernate.c3p0.timeout">1800</prop>
        <prop key="hibernate.c3p0.max_statements">50</prop>
        <prop key="hibernate.cache.provider_class">
                org.hibernate.cache.EhCacheProvider
        </prop>
        <prop key="hibernate.cache.use_second_level_cache">true</prop>
        <prop key="hibernate.cache.use_query_cache">true</prop>
    </props>
</property>
<property name="dataSource">
    <ref bean="dataSource" />
</property>

In my Entity

@Entity
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)

@Table(name = "TestPOJOCATEGORY")
@NamedQueries({
 @NamedQuery(name = "TestPOJOcategory.findAll", query = "SELECT h FROM TestPOJOcategory h"),
 @NamedQuery(name = "TestPOJOcategory.findById", query = "SELECT h FROM TestPOJOcategory h WHERE h.id = :id"),
 @NamedQuery(name = "TestPOJOcategory.findByCategoryname", query = "SELECT h FROM TestPOJOcategory h WHERE h.categoryname = :categoryname")})
public class TestPOJOcategory implements Serializable {

In My Dao

public List<TestPOJOcategory> getAllCategory(final String keyword, final int nFirst,
        final int nPageSize,
        final String sortColumnId,
        final boolean bSortOrder) {

  List<TestPOJOcategory> result = (List<TestPOJOcategory>) getHibernateTemplate().execute(new HibernateCallback() {
    public Object doInHibernate(Session session) {
      Criteria crit = session.createCriteria(TestPOJOcategory.class, "TestPOJOcategory")
       .add(Restrictions.ilike("categoryname", keyword))
       .addOrder(bSortOrder ? Order.asc(sortColumnId) : Order.desc(sortColumnId))
       .setFirstResult(nFirst).setMaxResults(nPageSize);
      System.out.println("why still call from DB? suppose to call from cache");
      return crit.list();
    }
  });
  return result;
}

echcache.xml

 <cache name="testonly.package.model.TestPOJOcategory"
        maxElementsInMemory="200"
        eternal="true"
        overflowToDisk="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
    />

Each time I call the dao, it will still call from DB. Why?

Was it helpful?

Solution

First of all, your System.out.println() statement will get executed every time whether or not 2nd level cache is accessed because such access takes place within list() method.

Secondly, Criteria - much like Query - does not automatically use 2nd level cache; configuration properties you've specified merely enable it to be used. You still need to explicitly mark each Query / Criteria instance as cacheable by calling setCacheable(true):

Criteria crit = ...;
crit.setCacheable(true);
return crit.list();

On a side note, since you're using HibernateTemplate you might as well use it right :-) and get rid of manual doInHibernate wrapper:

public List<TestPOJOcategory> getAllCategory(final String keyword, final int nFirst,
    final int nPageSize,
    final String sortColumnId,
    final boolean bSortOrder) {

  DetachedCriteria crit = DetachedCriteria.forClass(TestPOJOcategory.class);
  crit.add(Restrictions.ilike("categoryname", keyword))
   .addOrder(bSortOrder ? Order.asc(sortColumnId) : Order.desc(sortColumnId));
  getHibernateTemplate().setCacheQueries(true); // works on both queries and criteria
  return (List<TestPOJOcategory>) getHibernateTemplate()
   .findByCriteria(crit, nFirst, nPageSize);
}

OTHER TIPS

Well, using the second level cache doesn't mean that you can find an object in the cache based on any arbitrary HQL (or Criteria) query. The second cache is only used when accessing the object by its key or when navigating an object graph.

So, here, you'll need to use query caching (yes, there are 3 caches: the first level cache, the second level cache and the query cache). This needs:

session.createQuery("query").setCacheable(true); 

Or, when using Criteria:

session.createCriteria(...).add(...).setCacheable(true);

And hibernate properties set (which you have):

hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true 

Actually, I'd warmly suggest to check the following resources if you want to get a better understanding of the various caching mechanism Hibernate uses and of what Hibernate caches exactly (i.e. "dehydrated" entities):

The two first articles are a bit old but still apply. The later is more recent. All are good readings IMO.

If you want to know if a SQL statement gets executed, then turn on the show_sql property on (or the org.hibernate.SQL logger).

Otherwise, Hibernate caching is mainly by primary key. This makes is very useful when an object needs to be refreshed or many-to-one relationships are traversed. Keeping a cached result set for an arbitrary query consistent through random concurrent updates/inserts/deletes that may or may not impact the result set seems very complicated. Unless you have a performance problem I wouldn't recommend caching queries.

It looks like you may have missed configuring the cache on the hibernate level. It looks like you need to add the following to your hibernate configuration file to enable caching.

<cache usage=”read-only” />

You also may want to check this link out, it looks pretty good. http://blog.dynatrace.com/2009/03/24/understanding-caching-in-hibernate-part-three-the-second-level-cache/

Hope this is helpful!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top