Hibernate Second Level EHCache Example
In an application when the database traffic is very heavy, hibernate is well used because of its high performance. To overcome from this problem hibernate caching is the best technique. This technique is optimizing the database applications by caching the already loaded data from the database.
so the traffic between our application and the database will be reduced when the application want to access that data again.
Cache Types in Hibernate:
so the traffic between our application and the database will be reduced when the application want to access that data again.
Cache Types in Hibernate:
First-level cache
Second-level cache.
Hibernate Cache Implementations:
OSCache (Open Symphony Cache)
EHCache (Easy Hibernate Cache)
JBoss TreeCache
SwarmCache
Hibernate Caching Strategies:
Read-only.
Read-Write.
Nonstriict read-write.
Transactional.
First-level cache:-
First-level cache always associates with the Session object. Hibernate uses this cache by default. First level cache is enabled by default. Here, it processes one transaction after another one, it means it wont process one transaction many times. Mainly it is reducing the number of SQL queries it needs to generate within a given transaction i.e. instead of updating after every modification done in the transaction, it updates the transaction only at the end of the transaction.
Second-level cache:-
Second level cache was introduced in hibernate 3.0.Second-level cache always associates with the Session Factory object. Second level cache works while running the transactions, in between it loads the objects at the Session Factory level, so that those objects will available to the entire application, don’t bounds to single user. Since the objects are already loaded in the cache, whenever an object is returned by the query, at that time no need to go for a database transaction. We can use query level cache also.Hibernate Cache Implementations:-
a) OSCache (Open Symphony Cache) (org.hibernate.cache.OSCacheProvider)
- It is a powerful .
- It supports read-only and read/write caching.
- It supports memory- based and disk-based caching.
- It provides basic support for clustering via either JavaGroups or JMS.
b) EHCache (Easy Hibernate Cache) (org.hibernate.cache.EhCacheProvider)
- It is lightweight and that's why it is fast.
- It is Easy-to-use.
- It supports read-only and read/write caching.
- It supports memory-based and disk-based caching.
- It does not support clustering.
c) JBoss TreeCache (org.hibernate.cache.TreeCacheProvider)
- It is a powerful replicated and transactional cache.
- It is useful when we need a true transaction-capable caching architecture .
d)SwarmCache (org.hibernate.cache.SwarmCacheProvider)
- It is a cluster-based caching.
- It supports read-only or nonstrict read/write caching .
- It is very much appropriate for applications those have more read operations than write operations.
Hibernate Caching/Concurrency Strategies
A concurrency strategy is a way which is responsible for storing items of data in the cache and retrieving them from the cache.a) Read-only
- It is useful for those data which is frequently read but never updated.
- It is Simple.
- This is the best performer among the all caching strategy.
Advantage if this one is, It is safe for using in a cluster. Here is an example for using the read-only cache strategy.
Refer the below example:- < class name= "com.gaurav.bean.Customer" mutable= "true" > <cache usage= "read-only" /> .......................... </ class > |
b) Read-Write
- It is used, when our data needs to be updated frequently.
- It is having more overhead than read-only caches.
- It is never used if serializable transaction isolation level is required.
- In a JTA environment, for obtaining the JTA TransactionManager we must specify the property hibernate.transaction.manager_lookup_class.
- To use it in a cluster the cache implementation must support locking.
Here is an example for using the read-write cache strategy.
< class name= " .... > <cache usage= "read-write" /> .............................. <set name= "test" ... > <cache usage= "read-write" /> ................................ </set> </ class > |
C) Nonstrict read-write
- It is needed if the application needs to update data rarely.
- we must specify hibernate.transaction.manager_lookup_class to use this in a JTA environment .
Here is an example for using the nonstrict read-write cache strategy.
< class name= " .... > <cache usage= " nonstrict-read-write" /> ............................................... </ class > |
d) Transactional
- It supports only transactional cache providers such as JBoss TreeCache.
- It is only used in JTA environment.
Configuring Cache in Hibernate
We can use hibernate.cfg.xml file for the cache configuration. A typical configuration file is shown below.
<hibernate-configuration> <session-factory> ............................. <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> ............................. </session-factory> </hibernate-configuration> |
The name in <property> tag must be hibernate.cache.provider_class or cache.provider_class for activating second-level cache. We can use hibernate.cache.use_second_level_cache property, which allows you to activate and deactivate the second-level cache. By default, the second-level cache is activated and uses the EHCache.
Hibernate cache tag element
The <cache> element has the following
attributes
: <cache usage= " caching strategy" region= "RegionName" include= "all | non-lazy" /> |
- usage (mandatory) specifies the caching
strategy
: transactional, read-write, nonstrict-read-write or read-only. - region (optional) specifies the name of the second level cache region .
- include (optional) non-lazy specifies that properties of the entity mapped with lazy=”true” may not be cached when attribute-level lazy fetching is enabled.
Hibernate queries Caching
- For storing the most recent updates.
- For storing the results.
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM CUSTOMER");
query.setCacheable(true);
query.setCacheRegion("customer");
List users = query.list();
SessionFactory.closeSession();
Note: - This(query.setCacheRegion("customer")) code uses the method to tell Hibernate to store and look for the query in the customer area of the cache.
hibernate.cache.use_query_cache property We need to set in the hibernate.cfg.xml file to true like below :
<property name="hibernate.cache.use_query_cache">true</property>
Then, we can use the setCacheable() method on any query we wish to cache.
Hibernate second level cache example
Required files are as below:-- Customer.java [ Pojo class]
- Customer.hbm.xml
- ehcache.xml
- hibernate.cfg.xml
- log4j.properties
- HibernateSendLevelCacheTest.java
package com.gaurav.bean;
public class Customer {
private int customerId;
private String customerName;
private double expenditure;
/**
* @return the customerId
*/
public int getCustomerId() {
return customerId;
}
/**
* @param customerId
* the customerId to set
*/
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
/**
* @return the customerName
*/
public String getCustomerName() {
return customerName;
}
/**
* @param customerName
* the customerName to set
*/
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
/**
* @return the expenditure
*/
public double getExpenditure() {
return expenditure;
}
/**
* @param expenditure
* the expenditure to set
*/
public void setExpenditure(double expenditure) {
this.expenditure = expenditure;
}
}
Customer.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.gaurav.bean.Customer" table="customer">
<cache usage="read-only" />
<id name="customerId" column="CUSTOMER_ID" />
<property name="customerName" column="CUSTOMER_NAME" length="50" />
<property name="expenditure" column="TOTAL_EXPENDITURE" />
</class>
</hibernate-mapping>
ehcache.xml
<?xml version="1.0"?>
<ehcache>
<defaultCache maxElementsInMemory="100" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="200" />
<cache name="com.gaurav.bean.Customer" maxElementsInMemory="100" eternal="false"
timeToIdleSeconds="5" timeToLiveSeconds="200" />
</ehcache>
hibernate.cfg.xml
<?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/test</property>
<property name="hibernate.connection.username">root</property>
<property name="connection.password">root</property>
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="Customer.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=warn, stdout
log4j.logger.org.hibernate=debug
log4j.logger.org.hibernate.type=trace
### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=debug
HibernateSendLevelCacheTest.java
package com.gaurav.impl.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.gaurav.bean.Customer;
public class HibernateSendLevelCacheTest {
public static void main(String[] args) {
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session firstSession = sessionFactory.openSession();
Object object1 = firstSession.load(Customer.class, new Integer(1));
Customer customer1 = (Customer) object1;
System.out.println("Object Loaded first and here customer name is-->"
+ customer1.getCustomerName());
System.out.println("Object Loaded first and here customer id is-->"
+ customer1.getCustomerId());
System.out
.println("Object Loaded first and here customer expenditure is-->"
+ customer1.getExpenditure());
System.out.println("***** Object is loaded here *****");
firstSession.clear();
firstSession.close();
System.out.println("Thread.sleep called Status-Waiting......");
try {
Thread.sleep(10000);
} catch (Exception e) {
}
System.out
.println("----------------------------Waiting---------------------------------------------------------");
System.out.println("10 seconds compelted during wait");
Session secondSession = sessionFactory.openSession();
Object object2 = secondSession.load(Customer.class, new Integer(1));
System.out
.println("-------------------------------------------------------------------------------------");
Customer customer2 = (Customer) object2;
System.out
.println("Second time object loaded and here customer name is -->"
+ customer2.getCustomerName());
System.out
.println("Second time object loaded and here customer id is-->"
+ customer1.getCustomerId());
System.out
.println("Second time object loaded and here customer expenditure is-->"
+ customer1.getExpenditure());
System.out.println("***** Object loaded from the database *****");
secondSession.close();
Session thirdSession = sessionFactory.openSession();
Object object3 = thirdSession.load(Customer.class, new Integer(1));
System.out
.println("-------------------------------------------------------------------------------------");
Customer customer3 = (Customer) object3;
System.out
.println("Third time object loaded and here customer name is-->"
+ customer3.getCustomerName());
System.out
.println("Third time object loaded and here customer id is-->"
+ customer1.getCustomerId());
System.out
.println("Third time object loaded and here customer expenditure is-->"
+ customer1.getExpenditure());
System.out
.println("***** Object loaded from global cache successfully *****");
thirdSession.close();
sessionFactory.close();
}
}
Below is the project directory structure:-
About ehcache.xml
In ehcache.xml, if eternal=”true” then we should not write timeToIdealSeconds, timeToLiveSeconds,
hibernate will take care about these values, If you want to give values manually then we can
use eternal=''false'' and we can assign values into timeToIdealSeconds, timeToLiveSeconds manually,
a) timeToIdealSeconds = ''seconds'' means, if the object in the global cache is not using by any other class or object then it will be waited for some time we specified and deleted from the global cache if time is exceeds more than timeToIdealSeconds value.
b) timeToLiveSeconds = ''seconds'' means if once the time specified is completed then it will be removed from the global cache by hibernate.
c) <defaultCache … /> will reflects to all the pojo classes in our application, and we can also assign the ehcache values to specified pojo class by
<cache name=”– package name.pojo class name —” …….. />
Hibernate Caching Tips
- All the objects those are passed to methods save(), update() or saveOrUpdate() or those you get from load(), get(), list(), iterate() or scroll() will be saved into cache.
- evict() is used to delete the object from cache.
- flush() is used to synchronize the object with database.
- Session.clear() used to delete all objects from the cache .
- contains() used to find whether the object belongs to the cache or not.
- If the query wants to force a refresh of its query cache region, we should call Query.setCacheMode(CacheMode.REFRESH).