views:

328

answers:

4

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?

+6  A: 

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);
}
ChssPly76
may i know where should i put system.out.print to check the method is calling from db or cache?
cometta
here is what i do to check whether the query if from db or cache. use show_sql to check.
cometta
show_sql is correct; and you already have it in your configuration. If the SQL is not printed that means query results are retrieved from cache.
ChssPly76
for 2nd level cache and query cache. is it a required to create entity statement like above in ehcache.xml? i commented out the line and it still work
cometta
It's not **required** to have `ehcache.xml` at all - defaults will work. It's usually **good** to have it as you can specify settings more appropriate to your situations, though. Query / criteria caches use separate cache regions so they won't use settings you've specified above for entity. Check Hibernate / ehcache documentation for details on cache region names / configuration.
ChssPly76
for the above getAllCategory(..) before I return the List I need to do getHibernateTemplate().setCacheQueries(false) right? because only this cache query need to be cached.
cometta
Yes, you need to set it back to false before you invoke the query you don't want cached.
ChssPly76
Great answer! Helped me today to a solve similar nagging problem!
Derek Mahar
A: 

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!

ralphL
I'm using annotated class not hbm.xml. do i need to addd that line? where?
cometta
+4  A: 

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.

Pascal Thivent
thank you for pointing out the references. i already read those before posting
cometta
+1, good links. I haven't seen the last one before, very nice.
ChssPly76
+1  A: 

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.

FelixM