I am writing a blog on hibernate cache. I have read articles recently and writing here my findings. Hibernate cache is used to reduce interaction with database. We store data in cache and use it whenever application tries to interact with database. Hibernate at first search it in cache, if its not available in cache then it execute query on database. Basically we use two level cache.

First-Level Cache
Secondary Level Cache

Hibernate always uses first level cache. Its a mandatory cache because first level cache associates with session object uses it make all transaction.When hibernate commit many transactions in one table simultaneously, then cache store all queries in cache and update transactions one by one. It enhance performance of database.

Secondary level cache associate with Session factory object.
For better understanding you can follow this link.
HIbernate Tutorial

I am going to discuss second level cache with an example.I made a pojo class in java named room. Here is structure of class.

package com.vivek;

/**
 * Created by Vivek on 5/4/14.
 */
public class Room {
    int id;
    String roomName;

    public Room() {}

    public Room(String roomName) {
        this.roomName = roomName;
    }

    public void setRoomName(String roomName) {
        this.roomName = roomName;
    }

    public String getRoomName() {
        return roomName;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }
}

concurrency strategy is used to store objects in cache. We four type of strategy to store data in cache.
Transactional : If we need to store data in cache which will rarely update, we use transactional strategy.In transactional strategy we need to update database while transaction is in process.
Read Only: If we never need to update a database then we go for Read-Only.
Read Write: If we need both to read data in table and write data into table, we use this strategy.
Nonstrict read/write: When we need to update database rarely, we use this strategy.This is an asynchronous strategy.

In my example I am using ehcahce with read-write strategy. I am using these dependencies for this application.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hibernate-cache</groupId>
    <artifactId>hibernate-cache</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.2.7.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>4.2.7.Final</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.164</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.30</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.3.4.Final</version>
        </dependency>




    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>App</mainClass>
                    <arguments>
                        <argument>argument1</argument>
                    </arguments>
                    <systemProperties>
                        <systemProperty>
                            <key>myproperty</key>
                            <value>myvalue</value>
                        </systemProperty>
                    </systemProperties>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

After that I made xml file for hibernate configuration. In which I defined EhCacheProvider for second level cache.

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
        <hibernate-configuration>
    <session-factory>

        <!--Connection pool settings-->
        <property name="hibernate.c3p0.max_size">5</property>
        <property name="hibernate.c3p0.min_size">2</property>
        <property name="hibernate.c3p0.timeout">300</property> <!-- removes idle connections-->
        <property name="hibernate.c3p0.max_statements">50</property> <!--Max 50 prepared statements will be cached-->
        <property name="hibernate.c3p0.idle_test_period">3000</property> <!--time period after which an idle connection is tested-->

        <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="cache.provider_class">
            org.hibernate.cache.EhCacheProvider
        </property>

        <!--Logging configuration-->
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>

        <!--Mapping files-->
        <mapping resource="com/vivek/Person.hbm.xml"/>
        <mapping resource="com/vivek/Room.hbm.xml"/>

    </session-factory>
</hibernate-configuration>

I am using hbm file to create relation between pojo class and database. I am using mysql for database. Here is configuraation for Room.hbm.xml.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.vivek.Room"
           table="room"
            dynamic-insert="false"
            dynamic-update="false">

        <id name="id" column="id">
            <generator class="increment"/>
        </id>


        <property name="roomName" column="room_name" type="text"/>



    </class>
</hibernate-mapping>

For using cache I made a file ehcache.xml. By convention if we use second level cache using ehcache, it read its configuration from ehcache.xml. If you want change its name, you need to give path in hibernate.cfg.xml file.

Here is structure for ehcache.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <cache
            name="com.vivek.Person"
            maxEntriesLocalHeap="10000"
            eternal="false"
            timeToIdleSeconds="6"
            timeToLiveSeconds="200"/>
    <persistence strategy="localTempSwap"/>
</ehcache>

Using these configuration I made main file App.java where I made usage of cache.

package com.vivek.main;


import com.vivek.Room;
import org.apache.log4j.Logger;
import org.hibernate.Session;

/**
 * Created by Vivek on 5/4/14.
 */
public class App {
    private static final Logger log = Logger.getLogger(App.class);

    public static void main(String[] args) {
        Session session = HibernateUtil.getSessionFactory().openSession();

        Room room = (Room)session.load(Room.class,new Integer(1));

        System.out.println("room   " + room.getRoomName());
        System.out.println("Object loaded successfully");
        session.close();

        System.out.println("------------wait here-------------");

        try {
            Thread.sleep(6000);
        } catch (Exception e) {
            System.out.println("Exception  " + e);
        }

        System.out.println("waiting for 6 second has been completed");
        session = HibernateUtil.getSessionFactory().openSession();
        System.out.println("start transaction");
        room = (Room)session.load(Room.class,new Integer(1));

        System.out.println("room  " + room.getRoomName());
        System.out.println("object loaded from database....");
        session.save(room);
        session.close();

        session = HibernateUtil.getSessionFactory().openSession();
        room = (Room)session.load(Room.class,new Integer(1));

        System.out.println("Room   " + room.getRoomName());
        System.out.println("object loaded from cache");
        session.close();
    }
}

I suppose that in my database one value for id ‘1’ is already exist. So I load value from database first time. Second time I insert waiting condition for 6 second as I mentioned in ehcache.xml that after 6 second object will be removed from cache.

timeToIdleSeconds="6"

Then again load value from database and this time concurrently again made session and this time it load object from cache. This way in this project I used second level cache.