Working with a second-level cache

In the previous section, you learned about the first-level cache, which is enabled by default and whose scope is limited to a particular session.

Now, the scope of the second-level cache is SessionFactory, and we can use the cached objects across the different sessions that are created using this particular SessionFactory. Hibernate provides the option to either enable or disable the second-level cache.

Hibernate provides a facility to change the cache provider, which means that we can provide any cache provider that supports integration with hibernate. Ehcache is used as the default cache provider by hibernate. Apart from Ehcache, there are some other providers available that support integration with hibernate. They are listed as follows:

  • OSCache
  • SwarmCache
  • JBoss Cache

In this recipe, we will consider integration with Ehcache.

Getting ready

For this recipe to be successful, we need one more JAR file for Ehcache. We can download the Ehcache distribution from the official site, http://ehcache.org/downloads/. You can use the following Maven configuration for a Maven-based project:

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.9</version>
</dependency>

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

Enabling a second-level cache

We need to change the configuration.

To enable the second-level cache, we need to add two new mappings in the configuration (CFG) file.

The mappings are as follows:

<property name="hibernate.cache.use_second_level_cache">
  true
</property>
<property name="hibernate.cache.region.factory_class">
  net.sf.ehcache.hibernate.EhCacheRegionFactory
</property>

The first property tag is used to enable the second-level cache. We must set the value of the hibernate.cache.use_second_level_cache property to true.

Another tag is used to provide a cache provider class, which is vendor-specific. Here, we will set the value of the hibernate.cache.region.factory_class property to net.sf.ehcache.hibernate.EhCacheRegionFactory as we will use Ehcache here.

Adding a caching strategy using a POJO class

We need to explicitly state which class needs to be cached using the second-level cache and which strategy is to be used for this:

Source file: Employee.java

@Entity
@Table(name="employee")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
public class Employee {
    // fields and getters/setters
}

Here, we used the @Cache annotation on top of the Employee class to inform hibernate that the result of this class should be cached if any transaction is made for this class.

The usage attribute is used to provide a caching strategy. We can provide five caching strategies, which are defined in enum CacheConcurrencyStrategy:

  • CacheConcurrencyStrategy.READ_ONLY: This strategy is suitable where the data never changes but is required frequently.
  • CacheConcurrencyStrategy.NONSTRICT_READ_WRITE: This strategy is suitable for the applications that only rarely need to modify data.
  • CacheConcurrencyStrategy.READ_WRITE: This strategy is suitable for the applications that regularly need to modify data.
  • CacheConcurrencyStrategy.TRNSACTIONAL: The transactional cache strategy provides support to transactional cache providers such as JBoss TreeCache.

How to do it…

Now we will consider a basic example of the READ_ONLY caching strategy. Consider the following code:

Code

/* Line 1*/ Session session = sessionFactory.openSession();
/* Line 2 */ Employee employee = (Employee) session.load(Employee.class, new Long(1));
System.out.println(employee.toString());
/* Line 4 */ session.close();
    
/* Line 6 */ Session anotherSession = sessionFactory.openSession();
/* Line 7 */ Employee employee_dummy = (Employee) anotherSession.load(Employee.class, new Long(1));
System.out.println(employee_dummy.toString());
/* Line 9 */ anotherSession.close();

Output

Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from employee employee0_ where employee0_.id=?
Employee: 
  Id: 1
  Name: Yogesh
Employee: 
  Id: 1
  Name: Yogesh

How it works…

We will now take a look at how the second-level cache works with reference to the preceding code. Here, we opened a session to load Employee#1 in Line 1, and this session was closed in Line 4 after the loading was complete. Next, we opened a new session in Line 6 and tried to load the same Employee object. It's clear from the output that the object was loaded from the cache because in a first-level caching, objects are destroyed when the session is closed. However, here we got the same object without hitting the database.

The flow of a second-level caching is as follows:

  1. When hibernate tries to load a particular entity, it first looks for the first-level cache of the current session.
  2. It is returned if the requested entity is present in the first-level cache.
  3. If this particular entity is not found in the first-level cache, it will look for the second-level cache.
  4. If the entity is found in the second-level cache, it's returned. Hibernate also stores this entity in the particular session, so there is no need to go to the second-level cache on the next request.
  5. If the entity is not found in the second-level cache, hibernate hits the database and stores it in both the first and second-level caches and then returns it.
..................Content has been hidden....................

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