In the previous tutorials, we have discussed different states of hibernate object and also we discussed how load() and get() methods are working internally. Now we are going to discuss one more important topic in hibernate, what is hibernate cache and how it works exactly.
Hibernate Cache :
A cache is a local buffer. It improves the performance of the application by reducing the number of trips (hits) between Java application and database. Caching In hibernate are of 2 types :
- First Level Cache
- Second Level Cache
First Level Cache :
In Hibernate, when a session is opened then hibernate automatically opens a cache along with that session. When a session is closed then automatically cache also closed. Every session is associated with a corresponding cache. As a programmer we no need of doing any settings (configurations) either to enable or disable the first-level cache.
When a program wants an object from the database then hibernate first checks for that object in level1 cache. If that object does not exist in level1 cache then it checks in the second-level cache. If not exist in the second-level cache, then only hibernate goes to the database.
As we were discussed in the top 10 advantages of hibernate, caching in hibernate is the most powerful feature than compared with the other ORM frameworks. Hibernate also gives an excellent API to manage the states of objects too.
How Hibernate Cache Works?
As we discussed, when a session is opened then automatically hibernate opens a cache. The life cycle of the cache is completely managed by the hibernate itself.
For each and every session, there will be a separate cache is opened. So level 1 cache is also called a local cache. When we are loading an object, hibernate first checks for that object in the local cache. If not existed then only it goes to the database and load an object.
On the above diagram,
Step 1 : We are trying to get the Student data from the database by using session.get(Student.class, 101); In this step Hibernate goes to first level cache and checks for the Student. But as this is the first request, Student object is not available in the cache.
Step 2 : In step 2 hibernate goes to Database to get the Student object.
Step 3 : In step 3 hibernate get an object from the database and save that object in the cache.
Step 4 : In step 4 returns that object to program.
After that, whenever the program wants that Student object, hibernate will directly get that object from the cache itself. We can see that in the Step a and Step b. Hence using hibernate cache mechanism the performance of an application will be increased.
Hibernate Cache Example :
package com.onlinetutorialspoint.service;
import com.onlinetutorialspoint.pojo.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class DbOperations {
public static void main(String[] args) {
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
SessionFactory factory = configuration.buildSessionFactory();
Session session = factory.openSession();
Student student = (Student) session.get(Student.class, 111);
/**
* At the first time there is no Student Object in first level cache,
* hence hibernate will go to database and get the Student Object, we
* can find the select statements in the output.
*
*/
System.out.println("Student Name : " + student.getName());
System.out.println("Student Id : " + student.getId());
System.out.println("Student Roll Number : " + student.getRollNumber());
System.out.println("=================================");
/**
* Here we are using the same session object to get the Student Details,
* that are already existed in the first level cache hence Hibernate
* will get the details from Session Cache.
*
*/
Student student2 = (Student) session.get(Student.class, 111);
System.out.println("Student Name : " + student2.getName());
System.out.println("Student Id : " + student2.getId());
System.out.println("Student Roll Number : " + student2.getRollNumber());
session.close();
}
}
Output :
Oct 09, 2015 11:29:03 PM org.hibernate.envers.boot.internal.EnversServiceImpl configure
INFO: Envers integration enabled? : true
Hibernate: select student0_.id as id1_0_0_, student0_.name as name2_0_0_, student0_.rollnumber as rollnumb3_0_0_ from onlinetutorialspoint.student student0_ where student0_.id=? Student Name : John Student Id : 111 Student Roll Number : 7
================================================
Student Name : John Student Id : 111 Student Roll Number : 7
On the above example, if we observe output carefully to get the Student details for the first time to hibernate went to the database. We can find the database select query in the output. But in the second time the select query not executed, because the Students were taken from hibernate cache (First level cache) itself.
Suppose if want to read an object from the database only, but not from the cache then we can remove that object the cache by calling evict() method.
We can also delete all objects from the cache by calling clear() method.
Removing Objects from Hibernate Cache:
package com.onlinetutorialspoint.service;
import com.onlinetutorialspoint.pojo.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class DbOperations {
public static void main(String[] args) {
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
SessionFactory factory = configuration.buildSessionFactory();
Session session = factory.openSession();
Student student = (Student) session.get(Student.class, 111);
System.out.println("Student Name : " + student.getName());
System.out.println("Student Id : " + student.getId());
System.out.println("Student Roll Number : " + student.getRollNumber());
System.out.println("=================================");
Student student2 = (Student) session.get(Student.class, 111);
System.out.println("Student 2 Name : " + student2.getName());
System.out.println("Student 2 Id : " + student2.getId());
System.out.println("Student 2 Roll Number : " + student2.getRollNumber());
System.out.println("=================================");
session.evict(student);
Student student3 = (Student) session.get(Student.class, 111);
System.out.println("Student 3 Name : " + student3.getName());
System.out.println("Student 3 Id : " + student3.getId());
System.out.println("Student 3 Roll Number : " + student3.getRollNumber());
session.close();
}
}
Output :
INFO: Envers integration enabled? : true
Hibernate: select student0_.id as id1_0_0_, student0_.name as name2_0_0_, student0_.rollnumber as rollnumb3_0_0_ from onlinetutorialspoint.student student0_ where student0_.id=? Student Name : John Student Id : 111 Student Roll Number : 7
=================================
Student 2 Name : John Student 2 Id : 111 Student 2 Roll Number : 7
=================================
Hibernate: select student0_.id as id1_0_0_, student0_.name as name2_0_0_, student0_.rollnumber as rollnumb3_0_0_ from onlinetutorialspoint.student student0_ where student0_.id=? Student 3 Name : John Student 3 Id : 111 Student 3 Roll Number : 7
When the above program is executed, then two times hibernate goes to the database for loading an object.
when evict() method is called hibernate finds the object, whether it existed in cache or not based on id property.
Problem with the Hibernate Cache :
An only problem with the cache is if an object is updated in database explicitly or by another thread, then the changes are not automatically affected on the object stored in the cache.
It is the developer responsibility to refresh a session at regular intervals by calling session.refresh().
Happy Learning 🙂