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:
In this recipe, we will consider integration with Ehcache.
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>
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.
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.Now we will consider a basic example of the READ_ONLY
caching strategy. Consider the following 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();
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: