Once we execute a particular query using hibernate, it always hits the database. As this process may be very expensive, hibernate provides the facility to cache objects within a certain boundary.
The basic actions performed in each database transaction are as follows:
This process is repeated every time we request a database operation, even if it is for a simple or small query. It is always a costly transaction to hit the database for the same records multiple times. Sometimes, we also face some delay in receiving the results because of network routing issues. There may be some other parameters that affect and contribute to the delay, but network routing issues play a major role in this cycle.
To overcome this issue, the database uses a mechanism that stores the result of a query, which is executed repeatedly, and uses this result again when the data is requested using the same query. These operations are done on the database side. Hibernate provides an in-built caching mechanism known as the first-level cache (L1 cache).
Following are some properties of the first-level cache:
Session
object only; the other Session
objects cannot access it.Session.evict(Object object)
to remove single objects from the session cache.Session.clear()
method is used to clear all the cached objects from the session.Let's take a look at how the L1 cache works.
For this recipe, we will create an Employee
class and also insert some records into the table:
Source file: Employee.java
@Entity @Table public class Employee { @Id @GeneratedValue private long id; @Column(name = "name") private String name; // getters and setters @Override public String toString() { return "Employee: " + " Id: " + this.id + " Name: " + this.name; } }
Use the following table script if the hibernate.hbm2ddl.auto
configuration property is not set to create
:
Use the following script to create the employee
table:
CREATE TABLE `employee` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) );
We will assume that two records are already inserted, as shown in the following employee
table:
id |
name |
---|---|
|
|
|
|
Now, let's take a look at some scenarios that show how the first-level cache works.
Here is the code to see how caching works. In the code, we will load employee#1
and employee#2
once; after that, we will try to load the same employees again and see what happens:
System.out.println(" Loading employee#1..."); /* Line 2 */ Employee employee1 = (Employee) session.load(Employee.class, new Long(1)); System.out.println(employee1.toString()); System.out.println(" Loading employee#2..."); /* Line 6 */ Employee employee2 = (Employee) session.load(Employee.class, new Long(2)); System.out.println(employee2.toString()); System.out.println(" Loading employee#1 again..."); /* Line 10 */ Employee employee1_dummy = (Employee) session.load(Employee.class, new Long(1)); System.out.println(employee1_dummy.toString()); System.out.println(" Loading employee#2 again..."); /* Line 15 */ Employee employee2_dummy = (Employee) session.load(Employee.class, new Long(2)); System.out.println(employee2_dummy.toString());
Loading employee#1... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 1 Name: Yogesh Loading employee#2... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 2 Name: Aarush Loading employee#1 again... Employee: Id: 1 Name: Yogesh Loading employee#2 again... Employee: Id: 2 Name: Aarush
Here, we loaded Employee#1
and Employee#2
as shown in Line 2
and 6
respectively and also the print output for both. It's clear from the output that hibernate will hit the database to load Employee#1
and Employee#2
because at startup, no object is cached in hibernate. Now, in Line 10
, we tried to load Employee#1
again. At this time, hibernate did not hit the database but simply use the cached object because Employee#1
is already loaded and this object is still in the session. The same thing happened with Employee#2
.
Hibernate stores an object in the cache only if one of the following operations is completed:
Save
Update
Get
Load
List
In the previous section, we took a look at how caching works. Now, we will discuss some other methods used to remove a cached object from the session.
There are two more methods that are used to remove a cached object:
evict(Object object)
: This method removes a particular object from the sessionclear()
: This method removes all the objects from the sessionThis method is used to remove a particular object from the session. It is very useful. The object is no longer available in the session once this method is invoked and the request for the object hits the database:
System.out.println(" Loading employee#1..."); /* Line 2 */ Employee employee1 = (Employee) session.load(Employee.class, new Long(1)); System.out.println(employee1.toString()); /* Line 5 */ session.evict(employee1); System.out.println(" Employee#1 removed using evict(…)..."); System.out.println(" Loading employee#1 again..."); /* Line 9*/ Employee employee1_dummy = (Employee) session.load(Employee.class, new Long(1)); System.out.println(employee1_dummy.toString());
Loading employee#1... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 1 Name: Yogesh Employee#1 removed using evict(…)... Loading employee#1 again... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 1 Name: Yogesh
Here, we loaded an Employee#1
, as shown in Line 2
. This object was then cached in the session, but we explicitly removed it from the session cache in Line 5
. So, the loading of Employee#1
will again hit the database.
This method is used to remove all the cached objects from the session cache. They will no longer be available in the session once this method is invoked and the request for the objects hits the database:
System.out.println(" Loading employee#1..."); /* Line 2 */ Employee employee1 = (Employee) session.load(Employee.class, new Long(1)); System.out.println(employee1.toString()); System.out.println(" Loading employee#2..."); /* Line 6 */ Employee employee2 = (Employee) session.load(Employee.class, new Long(2)); System.out.println(employee2.toString()); /* Line 9 */ session.clear(); System.out.println(" All objects removed from session cache using clear()..."); System.out.println(" Loading employee#1 again..."); /* Line 13 */ Employee employee1_dummy = (Employee) session.load(Employee.class, new Long(1)); System.out.println(employee1_dummy.toString()); System.out.println(" Loading employee#2 again..."); /* Line 17 */ Employee employee2_dummy = (Employee) session.load(Employee.class, new Long(2)); System.out.println(employee2_dummy.toString());
Loading employee#1... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 1 Name: Yogesh Loading employee#2... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 2 Name: Aarush All objects removed from session cache using clear()... Loading employee#1 again... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 1 Name: Yogesh Loading employee#2 again... Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from Employee employee0_ where employee0_.id=? Employee: Id: 2 Name: Aarush
Here, Line 2
and 6
show how to load Employee#1
and Employee#2
respectively. Now, we removed all the objects from the session cache using the clear()
method. As a result, the loading of both Employee#1
and Employee#2
will again result in a database hit, as shown in Line 13
and 17
.