Hibernate Cache Levels

Hibernate has 2 Cache’s, First level default session cache and the Second level explicitly configured cache. The main purpose of Cache’s is to reduce the number of Database hits from the application.

In this tutorial, You will find a very Simple easy to follow example using ehcache configuration as second level cache in hibernate.

When does Hibernate Use Second level Cache ?

  1. When Hibernate Session try to load an entity, it looks for the value in first level cache. If the cached copy is present in the first level cache then it is returned on call to load() method.
  2. If there is no cached entity in first level cache then it looks in the second level cache. If the entity is cached in second level then it is returned as result of load() method. But before returning the entity, it is stored in first level cache, so that for the next invocation the entity is loaded from the first level cache and not the second again.
  3. If the entity is not found in first and the second level cache, then the entity data is fetched from the database itself and is also stored in both the caches before returning the response.

How do cache verify updated data ?

  1. Second level cache validate itself for modified entities, if modification has been done through hibernate session APIs.
  2. But in some cases where someone modifies the data directly inside the database then that data will not be cached itself in the second level cache until “timeToLiveSeconds” duration has passed for that cache region. In that case, you can invalidate the cache and let hibernate build it again.

Configure EhCache

1. Add ehcache dependency in pom.xml

<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-ehcache</artifactId>
     <version>5.4.11.Final</version>
</dependency>

2. Add ehcache properties in properties file

You can add the cache properties in any property files like the “application.properties” or you name it anything and keep it in the resource folder of the project.

In this example, i have placed the properties in a file called “db.properties”.

# Hibernate Second level Cache
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory

3. Add @ annotations in Entity Objects Class

For Example : Employee.java

add @Cacheable & @org.hibernate.annotations.Cache

package com.pt.entities;

import org.hibernate.annotations.CacheConcurrencyStrategy;

import javax.persistence.*;

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

    public Employee() {}

    public Employee(int id, String firstName, 
                    String lastName, String address) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
    }

    public int getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName( String first_name ) {
        this.firstName = first_name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName( String last_name ) {
        this.lastName = last_name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

4. Service method call

In the basic code example in our previous tutorial add the below method in DAO implementation layer.

We will create 2 sessions and try to load the same Employee for example of id=6.

private void getEmployee() {

System.out.println("We are inside getEmployee method...");

Session session = sessionFactory.openSession();
Employee emp = session.load(Employee.class,6);
System.out.println("Employee load 1st time");
System.out.println(emp.getId()+" "+emp.getFirstName()+" "
                   +emp.getLastName());

Session session2 = sessionFactory.openSession();
Employee emp2 = session2.load(Employee.class,6);
System.out.println("Employee load 2nd time");
System.out.println(emp2.getId()+" "+emp2.getFirstName()+" "
                   +emp2.getLastName());

}

5. Output

Observation : Please see carefully in the below output, you will find there is only one select query on 1st load time, and no select query call on second call of load method,
this means that 1st time when the entity is loaded, it is being loaded from the database and internally also sent to both the caches before returning the entity object, but the 2nd time the data was loaded from the second level Cache itself(why not from the First level cache – the answer is because since we are using 2 different session objects in this example).

INFO: HHH000490: Using JtaPlatform implementation: 
 [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
We are inside getEmployee method...
Employee load 1st time
Hibernate: select employee0_.id as id1_0_0_, employee0_.address as 
address2_0_0_, employee0_.first_name as first_na3_0_0_, 
employee0_.last_name as last_nam4_0_0_ from EMPLOYEE employee0_ 
where employee0_.id=?
6 Mak S
Employee load 2nd time
6 Mak S

Summary

In this tutorial, we learnt and experienced in details how hibernate cache’s work. Try out the above code in your system and let us know your experience in comments.
I hope you liked it !