Working with a first-level cache

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:

  1. The request reaches the database server via the network.
  2. The database server processes the query in the query plan.
  3. Now the database server executes the processed query.
  4. Again, the database server returns the result to the querying application through the network.
  5. At last, the application processes the results.

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:

  • It is enabled by default. We cannot disable it even if we want to.
  • The scope of the first-level cache is limited to a particular Session object only; the other Session objects cannot access it.
  • All cached objects are destroyed once the session is closed.
  • If we request for an object, hibernate returns the object from the cache only if the requested object is found in the cache; otherwise, a database call is initiated.
  • We can use Session.evict(Object object) to remove single objects from the session cache.
  • The Session.clear() method is used to clear all the cached objects from the session.

Getting ready

Let's take a look at how the L1 cache works.

Creating the classes

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;
  }
}

Creating the tables

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

1

Yogesh

2

Aarush

Now, let's take a look at some scenarios that show how the first-level cache works.

How to do it…

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:

Code

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());

Output

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

How it works…

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

There's more…

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 session
  • clear(): This method removes all the objects from the session

evict (Object object)

This 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:

Code

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());

Output

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.

clear()

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:

Code

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());

Output

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset