A Simple Hibernate Caching Example using OSCache and EHCache

In this example im trying to create a simple application using Hibernate’s caching feature. What is cache anyway? A cache is designed to reduce traffic between your application and the database by conserving data already loaded from the database and put it whether in memory or in file. Database access is necessary only when retrieving data that is not currently available in the cache. So basically not all queries are taken from database, but from cache instead.

Hibernate use EHCache for default caching, but now im trying to demonstrate both OSCache and EHCache caching library. But you can only use one of it at one time. Both of them only differ in caching configuration, but the rest are still the same.

First is a simple sql file, a java bean and its hibernate xml configuration

CREATE
    TABLE matakuliah
    (
        kodematakuliah VARCHAR(10) NOT NULL,        
        namamatakuliah VARCHAR(20),
        PRIMARY KEY (kodematakuliah)
    )
    ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT
INTO
    matakuliah
    (
        kodematakuliah,        
        namamatakuliah
    )
    VALUES
    (
        '123',        
        'ccc'
    );
package com.edw.bean;

public class Matakuliah  implements java.io.Serializable {

     public class Matakuliah  implements java.io.Serializable {

     private String kodematakuliah;
     private String namamatakuliah;

    public Matakuliah() {
    }

    public Matakuliah(String kodematakuliah) {
        this.kodematakuliah = kodematakuliah;
    }
    public Matakuliah(String kodematakuliah, String namamatakuliah) {
       this.kodematakuliah = kodematakuliah;      
       this.namamatakuliah = namamatakuliah;
    }
   
    // other setters and getters   
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class catalog="kampus" name="com.edw.bean.Matakuliah" table="matakuliah">

    <!-- caching configuration -->
    <cache usage="read-write" />
    
    <id name="kodematakuliah" type="string">
      <column length="10" name="kodematakuliah"/>
      <generator class="assigned"/>
    </id>
      
    <property name="namamatakuliah" type="string">
      <column length="20" name="namamatakuliah"/>
    </property>       
  </class>
</hibernate-mapping>

please take a look at line 7, im using read-write because my data sometimes get updated. If you are planning to have static data that never changes, use read-only.

Next is registering EhCacheProvider on hibernate.cfg.xml file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3307/kampus</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.autocommit">true</property>
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    <mapping resource="com/edw/bean/Matakuliah.hbm.xml"/>    
  </session-factory>
</hibernate-configuration>

create a java file to load your hibernate configuration file

package com.edw.util;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

public class HiberUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

and dont forget your ehcache.xml configuration

<?xml version="1.0" encoding="UTF-8"?>
<!--
    caching configuration
-->
<ehcache>
    <defaultCache
        maxElementsInMemory="10"
        eternal="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"/>
</ehcache>

and this is my java file to test hibernate’s caching ability

package com.edw.main.caching;

import com.edw.bean.Matakuliah;
import com.edw.util.HiberUtil;
import java.util.Date;
import org.hibernate.Session;

public class CachingMain {

    public CachingMain() {
    }   

    /**
     *  do some repeated queries for table Matakuliah
     *  query results are taken from cache memory instead of database     
     */
    private void withCache() {

        Session session = null;
        try {            
            for (int i = 0; i < 3; i++) {

                // open session
                session = HiberUtil.getSessionFactory().openSession();                

                // time needed
                long now = new Date().getTime();

                // select
                Matakuliah matakuliah = (Matakuliah)session.load(Matakuliah.class, "123");

                // print
                System.out.println("matakuliah "+matakuliah.getNamamatakuliah());
                System.out.println("Time : " + (new Date().getTime() - now) + " ms");

                // sleep for 3seconds
                Thread.sleep(3000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    public static void main(String[] args) {
        CachingMain main = new CachingMain();
        main.withCache();
    }
}

you can see in your console, if you use log4j, this is what happen when Hibernate is querying from cache instead of database

DEBUG org.hibernate.impl.SessionImpl:220 - opened session at timestamp: 5364197853302784
DEBUG org.hibernate.jdbc.ConnectionManager:404 - aggressively releasing JDBC connection
DEBUG org.hibernate.impl.SessionImpl:832 - initializing proxy: [com.edw.bean.Matakuliah#123]
DEBUG org.hibernate.cache.EhCache:68 - key: com.edw.bean.Matakuliah#123
DEBUG org.hibernate.engine.StatefulPersistenceContext:790 - initializing non-lazy collections
matakuliah ccc
Time : 1 ms

Moving from EhCache to OsCache is very simple, all you have to do is replacing 1 line in your xml file, and adding an oscache.properties file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3307/kampus</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.autocommit">false</property>
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="hibernate.cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    <mapping resource="com/edw/bean/Matakuliah.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

and this is my oscache.properties

cache.capacity=1000
cache.path=c:\\cache\\
cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.HashDiskPersistenceListener

this is what happen on my Netbeans console when im using OsCache

DEBUG org.hibernate.impl.SessionImpl:220 - opened session at timestamp: 5364208706285568
DEBUG org.hibernate.jdbc.ConnectionManager:404 - aggressively releasing JDBC connection
DEBUG org.hibernate.impl.SessionImpl:832 - initializing proxy: [com.edw.bean.Matakuliah#123]
DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:694 - get called (key=com.edw.bean.Matakuliah#123.com.edw.bean.Matakuliah)
DEBUG org.hibernate.engine.StatefulPersistenceContext:790 - initializing non-lazy collections
matakuliah ccc
Time : 1 ms

This is my project structure,

Hope it can help others. Have fun. (*)

Leave a Comment

Your email address will not be published.