views:

98

answers:

2

I'm getting no improvement in speed when using Ehcache with Hibernate

Here are the results I get when i run the test below. The test is reading 80 Stop objects and then the same 80 Stop objects again using the cache.

On the second read it is hitting the cache, but there is no improvement in speed. Any idea's on what I'm doing wrong?

Speed Test:

First Read: Reading stops 1-80 : 288ms
Second Read: Reading stops 1-80 : 275ms

Cache Info:

elementsInMemory: 79
elementsInMemoryStore: 79
elementsInDiskStore: 0

JunitCacheTest

public class JunitCacheTest extends TestCase  {

    static Cache stopCache;

    public void testCache()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans-hibernate.xml");
        StopDao stopDao = (StopDao) context.getBean("stopDao");

        CacheManager manager = new CacheManager();
        stopCache = (Cache) manager.getCache("ie.dataStructure.Stop.Stop");
        //First Read
        for (int i=1; i<80;i++)
        {
            Stop toStop = stopDao.findById(i);
        }
        //Second Read
        for (int i=1; i<80;i++)
        {
            Stop toStop = stopDao.findById(i);
        }


        System.out.println("elementsInMemory " + stopCache.getSize());
        System.out.println("elementsInMemoryStore " + stopCache.getMemoryStoreSize());
        System.out.println("elementsInDiskStore " + stopCache.getDiskStoreSize());

    }

        public static Cache getStopCache() {
        return stopCache;
    }
}

HibernateStopDao

    @Repository("stopDao")
    public class HibernateStopDao implements StopDao {

        private SessionFactory sessionFactory;

        @Transactional(readOnly = true)
        public Stop findById(int stopId) {

            Cache stopCache = JunitCacheTest.getStopCache();
            Element cacheResult = stopCache.get(stopId);

            if (cacheResult != null){

                return (Stop) cacheResult.getValue();
            }
            else{

                Stop result =(Stop) sessionFactory.getCurrentSession().get(Stop.class, stopId);
                Element element = new Element(result.getStopID(),result);
                stopCache.put(element);
                return result;
            }
        }
    }

ehcache.xml

   <cache name="ie.dataStructure.Stop.Stop"
    maxElementsInMemory="1000"
    eternal="false"
    timeToIdleSeconds="5200"
    timeToLiveSeconds="5200"
    overflowToDisk="true">
    </cache>

stop.hbm.xml

    <class name="ie.dataStructure.Stop.Stop" table="stops" catalog="hibernate3" mutable="false" >
     <cache usage="read-only"/>
            <comment></comment>
            <id name="stopID" type="int">

                <column name="STOPID" />
                <generator class="assigned" />
            </id>
            <property name="coordinateID" type="int">
                <column name="COORDINATEID" not-null="true">
                    <comment></comment>
                </column>
            </property>
            <property name="routeID" type="int">
                <column name="ROUTEID" not-null="true">
                    <comment></comment>
                </column>
            </property>
        </class>

Stop

public class Stop implements Comparable<Stop>, Serializable  {

    private static final long serialVersionUID = 7823769092342311103L;
    private Integer stopID;
    private int routeID;
    private int coordinateID;
    }
A: 

Hibernate will use the second level cache automatically, when you add the <cache> element to your mapping file. You don't need to explicitly manage the cache before/after fetching objects from your Session.

Have you tried with a larger number of objects? Benchmarks under a second are not terribly reliable.

mdma
+1  A: 

The first mistake I see is that you are handling a cache on top of Hibernate's second level cache that will be already caching Stop entities. That's just useless, the second level cache is transparent, you don't need to add extra classes (like Element here) or extra code. So the DAO method should be:

@Transactional(readOnly = true)
public Stop findById(int stopId) {
    return (Stop) sessionFactory.getCurrentSession().get(Stop.class, stopId);
}

And that's all, nothing more. I repeat: activating second level is declarative, you don't need to modify your code.

Second mistake: your current test won't actually hit the second level cache, the second loop uses the same Session and will get objects from... the Session (the first level cache), not from the second level cache. If you want to test the second level cache, use another session (i.e. close the first one and get another one from the session factory).

I'd recommend to activate logging on the category org.hibernate.cache to log all second-level cache activity and make sure things are working as expected.

Once sure, remove logging and rerun your (fixed) test on a bigger sample (x10 or x100).

Pascal Thivent