J2EE Caching configuration using Ehcache

Ehcache

Ehcache is an open source, standards-based cache that boosts performance, offloads your database, and simplifies scalability. It’s the most widely-used Java-based cache because it’s robust, proven, full-featured, and integrates with other popular libraries and frameworks. Ehcache scales from in-process caching, all the way to mixed in-process/out-of-process deployments with terabyte-sized caches.

As I write this post we are using Ehcache as second level caching in hibernate for a system with millions of daily transaction.

We will be using JPA  hibernate configuration for ehcahce.

Dependencies

 <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.5.Final</version>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>3.4.0</version>
        </dependency>

        <!-- Hibernate EHCache API -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.3.5.Final</version>
        </dependency>
        <!-- EHCache uses slf4j for logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.11</version>
        </dependency>
    </dependencies>

Persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="CachePU" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jta-data-source>CacheDataSource</jta-data-source>
        <class>com.f1soft.entities.User</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
            <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
            <property name="hibernate.cache.use_second_level_cache" value="true"/>
            <property name="hibernate.cache.use_query_cache" value="true"/>
            <property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml"/>
        </properties>
    </persistence-unit>
</persistence>

</properties>
</persistence-unit>
</persistence>

 ehcache.xml 

Create this file inside resource.

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true">

    <!-- By default, Ehcache stored the cached files in temp folder. -->
    <!-- <diskStore path="java.io.tmpdir" /> -->

    <!-- Ask Ehcache to store cache in this path -->
    <diskStore path="d:\\cache" />

    <!-- Sample cache named cache1 This cache contains a maximum in memory of 10000 elements, and will expire an element if it is idle for more than 5 minutes and lives for more than 10 minutes. If there are more than 10000 elements it will overflow to the disk cache, which in this configuration will go to wherever java.io.tmp is defined on your system. On a standard Linux system this will be /tmp" -->
    <defaultCache maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20" timeToIdleSeconds="10" timeToLiveSeconds="20" memoryStoreEvictionPolicy="LFU" transactionalMode="off">
        <persistence strategy="localTempSwap" />
    </defaultCache>

    <cache name="User" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20" timeToIdleSeconds="10" timeToLiveSeconds="20" memoryStoreEvictionPolicy="LFU" transactionalMode="off">
        <persistence strategy="localTempSwap" />
        <searchable/>
    </cache>

</ehcache>

Entities
User.java


import java.io.Serializable;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

/**
*
* @author rashim.dhaubanjar
*/
@Data
@Cacheable(true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "User")
@Entity
@Table(name = "USERINFO")
@NamedQueries({
@NamedQuery(name = "User.findAll", query = "select u from User u ", hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true")}),
@NamedQuery(name = "User.findById", query = "select u from User u where u.id = :id")
})
@XmlRootElement(name = "user")
public class User implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private long id;
@Column(name = "USER_NAME")
private String userName;
@Column(name = "USER_ADDRESS")
private String userAddress;

public User() {
}

public User(long id) {
this.id = id;
}

public User(String userName, String userAddress) {
this.userName = userName;
this.userAddress = userAddress;
}
}

UserDAO.java

import java.util.List;
import javax.ejb.Local;

/**
*
* @author rashim.dhaubanjar
*/
@Local
public interface UserDAO {

List&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;User&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; getAllUser();

User findById(long id);

void insertUser(User user);

public boolean updateUser(long id, User user);

}

UserDAO implementation

UserDAOImpl.java

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class UserDAOImpl implements UserDAO {

@PersistenceContext(unitName = "CachePU")
EntityManager em;

@Override
public List&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;User&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; getAllUser() {
return em.createNamedQuery("User.findAll")
.getResultList();
}

@Override
public User findById(long id) {
return (User) em.createNamedQuery("User.findById")
.setParameter("id", id)
.getSingleResult();
}

@Override
public void insertUser(User user) {
System.out.println("em:::::" + em);
em.persist(user);
}

@Override
public boolean updateUser(long id, User data) {
User user =  findById(id);
user.setUserName(data.getUserName());
user.setUserAddress(data.getUserAddress());
em.merge(user);
return true;
}
}

Let us create Rest web service to access

@GET
@Path("/addusers")
@Produces(MediaType.APPLICATION_XML)
public String insertUser() {
User user1 = new User("vvv", "KTM");
User user2 = new User("ccc", "BKT");
User user3 = new User("xxx", "PTN");
System.out.println("userdao:::::::" + userDAO);
userDAO.insertUser(user1);
userDAO.insertUser(user2);
userDAO.insertUser(user3);
return "success";
}

@GET
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public List&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;User&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; getUser() {
List&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;User&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; user = new ArrayList&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;();
int size = CacheManager.ALL_CACHE_MANAGERS.get(0)
.getCache("User").getSize();
System.out.println("cahce size  all users :::::::::" + size);

Cache cache = CacheManager.getInstance().getCache("User");

user = userDAO.getAllUser();
return user;
}

Learn more in Ehcache Official website