Caching of hibernate

Recently, I faced a task related to caching queries in Hibernate framework. I would like to tell about various types of caches in hibernate and how to use and tune them.

First, there are tree cache levels:

Session level cache

According to its name, it is used during one session to database. Each session has own cache and when a session is closed, a cache is cleaned up. To be more clear, I list an example below:

Session session = HibernateUtil.getSessionFactory().openSession();
try {
    Criteria criteria = session.createCriteria(Account.class);
    criteria.add(Restrictions.eq("id", id));
    Account firstAccount = (Account) criteria.uniqueResult();
    Account secondAccount = (Account) criteria.uniqueResult();
} finally {
    session.close();
}

In this case, we see only query to a database. The second call criteria.uniqueResult() returns a value from a cache. The session cache level is enabled by default, and you have to do nothing to use it in contrast to other ones.
Hibernate framework does not provide implementations for second cache level and query cache level. In order to use them, you have to add some third-party libraries to your project.

The second level cache

This type of cache, or it is also so called sessionFactory affects all sessions. By default, it is disabled. As I said before, you should add some implementation of the cache. I use ehcache but you can use whatever you want. It is worth to mention, the configuration in the article is tested with hibernate 4.0.

I add some dependencies to my pom.xml:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>${hibernate.version}</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>${hibernate.version}</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.11</version>
</dependency>

and also add some parameters to hibernate configuration:

<property name="hibernate.cache.use_second_level_cache">
  true
</property>
<property name="hibernate.cache.region.factory_class">
  org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
</property>
<property name="net.sf.ehcache.configurationResourceName">
  ehcache.xml
</property>

To tune Ehcache, you should create a file ehcache.xml with parameters:

<ehcache>
  <diskStore path="java.io.tmpdir"/>
  <defaultCache
            maxElementsInMemory="100000"
            eternal="false"
            statistics="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            diskPersistent="false"
            diskSpoolBufferSizeMB="500"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

To avoid misunderstanding, I should to give some remarks.

It is almost all what we have to do. The last thing is to say hibernate that which entities we want to cache.
If we set mapping via xml, add an option <cache usage="read-write"/>, but if you use annotations, you should add @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) to an entity class.

A usage parameter can have parameters:

Query level cache

To use the query level cache, you should add an implementation to your project as well. Ehcache is an appropriate one and the configuration from previous section is legal for a query level cache. Also, you should add <property name="hibernate.cache.use_query_cache">true</property> to your hibernate configuration and that is all. Each time when you want queries to be cached, you should just call setCacheable(true) for them.