What is Hibernate Caching?

Until now we have discussed all the important concepts related to Hibernate Framework. The main goal of using Hibernate Framework is to reduce writing queries for persisting data instead of, just use the Object and Map it with the tables in the database.

But, We as a developer want our code to run fast and allow our Framework to limit hitting the database in a single transaction. So, here comes the important concept of caching. In this article, we will cover How Caching works in Hibernate.

What is Caching in Hibernate?

Caching in Hibernate is a way to increase the performance of your application. As we have seen above, we as a developer want our application to be fast. For this, we have a catching mechanism provided by Hibernate Framework. Two main importance of Caching.

  • Caching improves the speed of the application.
  • Caching limits the number of queries hit to the database.

Consider the following scenario, When you want to fetch data from the database you hit the database with the query and you get the data. once again if you want to fetch then again you hit the database. Due to this, your database gets hit by the query many times which reduces the speed of the application as shown in the following figure.

To avoid this situation, Hibernate provides us a caching mechanism where the cache memory is placed between your application and database and is used to store data retrieved from the database in order to avoid hitting queries to the database as shown in the following diagram.

Hibernate provides us two Mechanism of caching:

What is First Level Cache?

The First level Cache is related to Session Object.

  • When the Session object is used in the code it caches the object in session till you close the session.
  • So, whenever you want to fetch the data the object will be store in the Session Object. 
  • If the session is closed, all your object being cached will be lost.
  • It is the default caching.

When we hit the database with the query for the first time, the result is stored in the First Level cache. if once again, we hit the query with the same object the result now will be loaded from the First level cache and no query will be executed.

Example of First Level Cache

In this example, we will create a Table and we will see the working of the First level cache.

Let us first create a configuration file hibernate.cfg.xml file. When we want to create a table Just write create like this- <property name=”hbm2ddl.auto”>create</property> and then replace it with update(otherwise it will give an error).

<?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>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/college</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">khan</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>


    <property name="hibernate.c3p0.min_size">10</property>
    <property name="hibernate.c3p0.max_size">100</property>
    <property name="hibernate.c3p0.acquire_increment">10</property>
    <property name="hibernate.c3p0.timeout">10</property>
    <property name="hibernate.c3p0.">10</property>


    <mapping class="com.abc.Student" />
    



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

Now Create a java Class Student for setting and getting data. We are creating annotated-based classes so we won’t need a mapping file now. (for annotation you can see the previous article How to use Annotation in Hibernate?)

Student.java

In this class Just write the @Entity and @Table followed by table name.

package com.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity // specifies that class in an entity
@Table(name = "student") // defines the table
public class Student {

  @Id // indicate it is a primary key of the table.
  @GeneratedValue(strategy = GenerationType.IDENTITY) // annotation is to
                            // configure the way of
                            // increment of the
                            // specified
                            // column(field).
  @Column(name = "id")
  private int id;

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

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

  @Column(name = "collegename")
  private String cn;

  public int getId() {
    return id;
  }

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

  public String getNameOfStudent() {
    return nameOfStudent;
  }

  public void setNameOfStudent(String nameOfStudent) {
    this.nameOfStudent = nameOfStudent;
  }

  public String getAdd() {
    return add;
  }

  public void setAdd(String add) {
    this.add = add;
  }

  public String getCn() {
    return cn;
  }

  public void setCn(String cn) {
    this.cn = cn;
  }

  public Student() {
    super();
  }

  @Override
  public String toString() {
    return "Student [id=" + id + ", nameOfStudent=" + nameOfStudent + ", add=" + add + ", cn=" + cn + "]";
  }
  

}

Now, Create the main Test.java class

In this class, we will get the student id from the database using the session.get() method.

package com.abc;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Test {

  public static void main(String[] args) {
      SessionFactory factory = new Configuration().configure().buildSessionFactory();
        Session session = factory.openSession();
        session.beginTransaction();
       
     Student student = (Student) session.get(Student.class, 1);
     System.out.println(student);
     //Once again get the same id.
     Student student1 = (Student) session.get(Student.class, 1);
     System.out.println(student1);
     session.close();
  }
}
  • on line no. 17, we are getting student id:1 using session. get(Student.class,1). Now, It will create a query by hitting the database and will fetch student information with id:1.
  • on line no. 20, Once again we need that student information, so now it won’t create a query because the data is stored in the session object until the session is closed.

Output:

/*************OUTPUT*********************\
Hibernate: select student0_.id as id0_0_, student0_.address as address0_0_, student0_.collegename as collegen3_0_0_, student0_.name as name0_0_ from student student0_ where student0_.id=?
Student [id=1, nameOfStudent=Harry, add=UK, cn=hogwarts]
Student [id=1, nameOfStudent=Harry, add=UK, cn=hogwarts]

Thus, As we can see in the output only one time the query is fired. this is How First Level Cache is done which is a default caching mechanism.

What is Second-level Cache?

The second-level cache is related to Session Factory.

  • As we have seen in the first level caching, when we close the session all data is lost unlike it, in the second-level cache even if the session is closed the query is fired only once, and the data is not lost because the data is in sessionFactory.
  • Here, It is created in the Session factory scope.

In this, we need two follow some steps to achieve the Second Level Caching:

  • First, we need a Concurrency Strategy.
  • Next, we need a Cache provider.

What is Concurrency Strategy?

A concurrency strategy stores the data into the cache and retrieves data from the cache. These are the following 4 ways we can use.

What is a cache provider?

There are different vendors that provide the implementation of Second Level Cache

  • EH Cache
  • JBoss Cache
  • OS Cache
  • Swarm Cache

Example of Second Level Cache

In this example, we will create a Table and we will see the working of the Second level cache.

If you are creating a maven project then you need to download two dependencies:

  • ehcache
  • hibernate-ehcache dependencies.

Let us first create a configuration file hibernate.cfg.xml file. When we want to create a table Just write create like this- <property name=”hbm2ddl.auto”>create</property> and then replace it with update(otherwise it will give an error).

<?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>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/college</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">khan</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

    <property name="hibernate.show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="cache.use_second_level_cache">true</property>
    <property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    <property name="hibernate.c3p0.min_size">10</property>
    <property name="hibernate.c3p0.max_size">100</property>
    <property name="hibernate.c3p0.acquire_increment">10</property>
    <property name="hibernate.c3p0.timeout">10</property>
    <property name="hibernate.c3p0.">10</property>


    <mapping class="com.SecondLevel.Student" />
    



  </session-factory>
</hibernate-configuration>
  • on line no. 16: we have used <property name=“cache.use_second_level_cache”>true</property> to enable Second Level Cache.
  • on line no. 17: we will get “org.hibernate.cache.ehcache.EhCacheRegionFactory”  to implement Second Level Cache.

Now Create a java Class Student for setting and getting data. We are creating annotated-based classes so we won’t need a mapping file now. (for annotation you can see the previous article How to use Annotation in Hibernate?)

Student.java

In this class Just write the @Entity and @Table followed by table name. Here, we have used the @Cacheable and
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) to enable second-level caching.

package com.SecondLevel;

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.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;



@Entity // specifies that class in an entity
@Table(name = "student") // defines the table
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Student {

  @Id // indicate it is a primary key of the table.
  @GeneratedValue(strategy = GenerationType.IDENTITY) // annotation is to
                            // configure the way of
                            // increment of the
                            // specified
                            // column(field).
  @Column(name = "id")
  private int id;

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

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

  @Column(name = "collegename")
  private String cn;

  public int getId() {
    return id;
  }

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

  public String getNameOfStudent() {
    return nameOfStudent;
  }

  public void setNameOfStudent(String nameOfStudent) {
    this.nameOfStudent = nameOfStudent;
  }

  public String getAdd() {
    return add;
  }

  public void setAdd(String add) {
    this.add = add;
  }

  public String getCn() {
    return cn;
  }

  public void setCn(String cn) {
    this.cn = cn;
  }

  public Student() {
    super();
  }

  @Override
  public String toString() {
    return "Student [id=" + id + ", nameOfStudent=" + nameOfStudent + ", add=" + add + ", cn=" + cn + "]";
  }
}

Now, Create the main Test.java class

In this, we will open the session two times and see whether caching is implemented.

package com.SecondLevel;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cache.ehcache.EhCacheRegionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Hello world!
 *
 */
public class Test {
  public static void main(String[] args) {
    
    SessionFactory factory = new Configuration().configure().buildSessionFactory();

    Session session = factory.openSession();
    Student student = (Student) session.get(Student.class, 1);
    System.out.println(student);
    session.close();
    Session session2 = factory.openSession();
    Student student1 = (Student) session2.get(Student.class, 1);
    System.out.println(student1);
    session2.close();
  }
}
  • on line no. 17-19, we are opening a session and getting student id:1 using the session. get(Student.class,1). Now, It will create a query by hitting the database and will fetch student information with id:1.
  • on line no. 20, we have closed the session object.
  • on line no. 21, Once again we need that student information, so now it won’t create a query because the data is stored in the Session Factory object.

Output:

Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.address as address0_0_,
        student0_.collegename as collegen3_0_0_,
        student0_.name as name0_0_ 
    from
        student student0_ 
    where
        student0_.id=?
Student [id=1, nameOfStudent=Harry, add=UK, cn=hogwarts]
Student [id=1, nameOfStudent=Harry, add=UK, cn=hogwarts]

Thus, we can see here, that Only a one-time query is fired and this is how we implement second-level caching.

Thus, this was all about First and Second Level Caching in detail. In the next article of his tutorial, we will discuss Batch processing in Hibernate.