As seen in the previous post How to configure EhCache in Java, we will see how to configure ehCache as Second level Cache in Hibernate.
ORM Framework like hibernate provides cache mechanism to avoid number of queries made to database, which in turn increase the performance of web application.
Hibernate provides two layers of cache mechanism –
First Level Cache – Works in Session scope, enabled by default.
Second Level Cache – We need to configure the second level cache and it is available in session factory scope.
In this post we will see how to configure the ehCache as Second Level Cache in Hibernate and store/retrieve elements from second level cache.
Let's Start –
1) What is EhCache – As discussed in previous article ehCache is popular open source java cache mechanism which can be used as second level cache in Hibernate. ehCache can be downloaded from - http://www.terracotta.org/products/enterprise-ehcache. Below is maven dependency for ehCache –
2) Hibernate configuration -
To download the hibernate 3.3.2.GA version from –
http://sourceforge.net/projects/hibernate/files/hibernate3/3.3.2.GA/
3) Configure EhCache in Hibernate –
Steps to enable ehcache in Hibernate -
- Enable ehCache in Hibernate. Need to provide the configure in hibernate.cfg.xml
- Configure the entity object either in hbm.xml files or using annotation by choosing appropriate caching strategy
- Enable query caching mechanism
- If needed define the ehcache.xml to over the default values.
Let's understand by example in detail -
Note : In Order to run the application, you need to download the MySql database and should be working and able to connect. Need to create the database and Table by using below commands, which has been used in hibernate.cgf.xml
create database hibernatedemo create table TRADE(ID int(10),NAME VARCHAR(50));
1. Hibernate Configuration File –
In Order to configure ehcache in hibernate need to perform in two steps –
- Enable second level cache in hibernate.cgf.xml
- Specify the second level cache provider.
<?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.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatedemo</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">create</property> <!-- <property name="hibernate.cache.use_second_level_cache">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> <mapping class="code.desk.entity.DummyTrade"></mapping> </session-factory> </hibernate-configuration>
2. Configure Entity Objects –
If we are using hbm.xml file then we can configure as –
<class name=" code.desk.entity.DummyTrade " table="TRADE"> <cache usage="read-write"/> </class>
If we are using annotation based configuration then we can use the following code snippet–
In Order to define caching strategy we need to put the following statement
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="dummyTrade")
package code.desk.entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.UniqueConstraint; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @Entity (name = "dept") @Table(name = "TRADE", uniqueConstraints = { @UniqueConstraint(columnNames = "ID"), @UniqueConstraint(columnNames = "NAME") }) @Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="dummyTrade") public class DummyTrade implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "ID", unique = true, nullable = false) private Integer id; @Column(name = "NAME", unique = true, nullable = false, length = 100) private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3. Define the EhCache Configuration File –
As per the property defined in hibernate.cgf.xml, need to configure ehcache.xml.
<property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property>
As Defined in Cache configuration the cache name should be same as region name defined in DummyTrade entity.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"> <diskStore path="c:\temp\cache"/> <cache name="dummyTrade" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="5" timeToLiveSeconds="10" overflowToDisk="true" /> </ehcache>
4. Hibernate Utility -
HibernateUtility class use to get the Singleton Instance of SessionFactory.
package code.desk.util; import java.io.File; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; public class HibernateUtility { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { // Create the SessionFactory from hibernate.cfg.xml return new AnnotationConfiguration().configure(new File("hibernate.cgf.xml")).buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void shutdown() { // Close caches and connection pools getSessionFactory().close(); } }
5. Finally Test the Functionality -
In order to understand better I kept example easy and simple. Object stored in first level cache associated with session but objects stored in second level cache remains beyond the session as well.
In the below example, first we load the entity, which triggers database call and store it into the first level cache and second level cache.
When try to load the same entity again, it first look into the first level cache and if found it returns, this doesn't make any database call.
Now in order to test second level cache, we close the first session, which make sure the entity is not getting load from first level cache. Now again create the another session and try to load the entity, you can see the output, it will load from the second level cache and doesn't make the call to database.
Below is the code snippet –
package code.desk.test; import org.hibernate.Session; import org.hibernate.stat.Statistics; import code.desk.entity.DummyTrade; import code.desk.util.HibernateUtility; public class TestHibernateEhcacheMain { public static void main(String[] args) { insertDataToDB(); Statistics statistics = HibernateUtility.getSessionFactory().getStatistics(); try { // Enable the hibernate statics System.out.println("Is statics enabled "+statistics.isStatisticsEnabled()); statistics.setStatisticsEnabled(true); System.out.println("Is statics enabled "+statistics.isStatisticsEnabled()); //Open the hibernate session Session session = HibernateUtility.getSessionFactory().openSession(); session.beginTransaction(); //fetch the department entity from database first time DummyTrade department = (DummyTrade) session.load(DummyTrade.class, new Integer(1)); System.out.println(department.getName()); //fetch the department entity again; Fetched from first level cache department = (DummyTrade) session.load(DummyTrade.class, new Integer(1)); System.out.println(department.getName()); //Let's close the session session.getTransaction().commit(); session.close(); //Try to get department in new session Session anotherSession = HibernateUtility.getSessionFactory().openSession(); anotherSession.beginTransaction(); //Here entity is already in second level cache so no database query will be hit department = (DummyTrade) anotherSession.load(DummyTrade.class, new Integer(1)); System.out.println(department.getName()); anotherSession.getTransaction().commit(); anotherSession.close(); } finally { System.out.println(statistics.getEntityFetchCount()); //Prints 1 System.out.println(statistics.getSecondLevelCacheHitCount()); //Prints 1 HibernateUtility.shutdown(); } } private static void insertDataToDB() { Session session = HibernateUtility.getSessionFactory().openSession(); session.beginTransaction(); DummyTrade department = new DummyTrade(); department.setName("Human Resource"); session.save(department); session.getTransaction().commit(); session.close(); } }
This post is written by
Soumitra Pathak - Linkedin, Facebook
He is a freelance writer, loves to explore latest features in Java technology.
No comments:
Post a Comment