SpringBoot EhCache
Before going to deep, lets understand cache in Hibernate
Hibernate Cache
In Hibernate, Every fresh session having its own cache memory, Caching is a mechanism for storing the loaded objects into a cache memory.
The advantage of cache mechanism is, whenever again we want to load the same object from the database then instead of hitting the database once again, it loads from the local cache memory only, so that the no. of round trips between an application and a database server got decreased.
It means caching mechanism increases the performance of the application.
In hibernate we have two levels of caching
-
First Level Cache (Session Cache)
-
Second Level Cache (Session Factory Cache/ JVM Level Cache)
1.First Level Cache
-
By default, for each hibernate application, the first level cache is automatically enabled. We can’t Enable/Disable first level cache
-
the first level cache is associated with the session object and scope of the cache is limited to one session only
-
When we load an object for the first time from the database then the object will be loaded from the database and the loaded object will be stored in the cache memory maintained by that session object
-
If we load the same object once again, with in the same session, then the object will be loaded from the local cache memory not from the database
-
If we load the same object by opening other session, then again the object will load from the database and the loaded object will be stored in the cache memory maintained by this new session
Example:
Session session = factory.openSession();
Object ob1 = session.get(Actor.class, new Integer(101)); //1
Object ob2 = session.get(Actor.class, new Integer(101));//2
Object ob3 = session.get(Actor.class, new Integer(101));//3
session.close();//4
Session ses2 = factory.openSession();
Object ob5 = ses2.get(Actor.class, new Integer(101));//5
1,
We are loaded object with id 101, now it will load the object from the
database only as its the first time, and keeps this object in the session cache
2,3
i tried to load the same object 2 times, but here the object will be loaded
from the stored cache only not from the database, as we are in the same session
4,
we close the first session, so the cache memory related this session also
will be destroyed
5,
again i created one new session and loaded the same object with id 101, but
this time hibernate will loads the object from the database
if we want to remove the objects that are stored in the cache memory, then we
need to call either evict()
or clear() methods
2.Second Level Cache
Whenever we are loading any object from the database, then hibernate verify whether that object is available in the local cache(first level cache) memory of that particular session, if not available then hibernate verify whether the object is available in global cache(second level cache), if not available then hibernate will hit the database and loads the object from there, and then first stores in the local cache of the session , then in the global cache
SessionFactory holds the second level cache data. It is global for all the session objects and not enabled by default.
Different vendors have provided the implementation of Second Level Cache
-
EH Cache
-
OS Cache
-
Swarm Cache
-
JBoss Cache
Hibernate EHCache Example
To enable second level cache in the hibernate, then the following 3 changes are required
1.Add provider class in hibernate configuration file
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
2.Configure cache element for a class in hibernate mapping file
<cache usage="read-only" />
-
read-only: caching will work for read only operation.
-
nonstrict-read-write: caching will work for read and write but one at a time.
-
read-write: caching will work for read and write, can be used simultaneously.
-
transactional: caching will work for transaction.
3.create xml file called ehcache.xml and place where you have mapping and configuration xml’s
Example:
public class Employee {
private int eid;
private String name;
private String address;
//Setters & Getteers
}
Employee.hbm.xml
<hibernate-mapping package="cache">
<class name="Employee" table="employee">
<cache usage="read-only" />
<id name="eid" column="eid">
<generator class="native"></generator>
</id>
<property name="name"></property>
<property name="address"></property>
</class>
</hibernate-mapping>
ehcache.xml
<?xml version="1.0"?>
<ehcache>
<defaultCache maxElementsInMemory="100"
eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="200" />
<cache name="cache.Employee" maxElementsInMemory="100"
eternal="false" timeToIdleSeconds="5" timeToLiveSeconds="200" />
</ehcache>
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property> Driver Class, URL, Username, password, etc </property>
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<mapping resource="cache/employee.hbm.xml" />
</session-factory>
</hibernate-configuration>
CacheDemo.java
package cache;
import org.hibernate.*;
import org.hibernate.cfg.*;
public class CacheDemo {
public static void main(String[] args) {
//1.Load Configuration
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");
//2.Create Session
SessionFactory sf = cfg.buildSessionFactory();
Session session = sf.openSession();
//3.Perform Operations
Object ob = session.load(Employee.class, new Integer(1));
Employee bo = (Employee) ob;
System.out.println("SELECTED DATA\n ================");
System.out.println("SNO : "+bo.getEid());
System.out.println("NAME : "+bo.getName());
System.out.println("ADDRESS : "+bo.getAddress());
}
}
SpringBoot Cache
EhCache is an open-source and Java-based cache. It is used to boost performance. Its current version is 3. EhCache provides the implementation of the JSR-107 cache manager. Features of EhCache are given below:
- It is fast, lightweight, Flexible, and Scalable.
- It allows us to perform Serializable and Object
- It also offers cache eviction policies such as LRU, LFU, FIFO,
EhCaching Storage Tiers are as follows:
- On-Heap Store: Java heap memory is used to store cache entries.
- Off-Heap Store: It stores cache entries into primary memory (RAM).
- Disk Store: It uses a disk to store cache entries.
- Clustered Store: Remote server is used to store cache entries.
EhCache Usage Patterns:
Access patterns used by EhCache are given below:
- Cache-aside: It can be used to read and update operations of data to and from the data store.
- Cache-as-SoR (system-of-record): This pattern delegates SOR reading and writing activities to the cache so that the application code is absolved of this responsibility.
- Read-through: This pattern copies the cache-aside pattern while reading data from the cache.
- Write-through: This pattern copies the cache-aside pattern while writing data in the cache.
- Write-behind: It is a caching strategy in which the cache layer itself connects to the backing database.
Points to remember while using EhCaching:
1. We need to add the following dependencies in pom.xml.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.6.1</version></dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>
2. Next we have to open the application.properties file and configure the EhCache by using the following property.
configuring ehcache.xml
spring.cache.jcache.config=classpath:ehcache.xml
3. The @EnableCaching annotation triggers a post-processor that inspects every Spring bean for the presence of caching annotations methods that are public. If such an annotation is found, a proxy will be automatically created to intercept the method call and hence handle the caching behavior accordingly. We can use @EnableCaching annotation for enabling EhCaching as follows:
@Configuration
// used for enabling caching
@EnableCaching
public class CacheConfig {
}
4. This method-level annotation lets Spring Boot know that the value returned by the annotated method can be cached. Whenever a method marked with this @Cacheable is called, the caching behavior will be applied. In particular, Spring Boot will then check whether the method has been already invoked for the given arguments. This involves looking for a key that is generated using the method parameters by default. If no value is found in the cache related to the method for the computed key then the target method will be executed normally. Otherwise, the cached value will be immediately returned. @Cacheable comes with many parameters, but the easy way to use it is to annotate a method with the annotation and parameterize it with the name of the cache where the results will be stored. @Cacheable Annotation indicates that the result of invoking a method or all methods inside a class can be cached.
5. We need to create an hcache.xml file that contains the information related to the cache such as the name of the cache, no of the element in the memory, and time to live data in the cache, etc.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<diskStore path="D:\\cache" />
<cache name="cache1"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
</ehcache>
Example Project
An example of spring boot EhCaching is as follows.
Main class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.codippa")
public class CachingApplication {
public static void main(String[] args) {
SpringApplication.run(CachingApplication.class, args);
}
}
public class Post {
private Integer postId;
private String title;
public Post(Integer postId, String title)
{
this.postId = postId;
this.title = title;
}
public Integer getPostId() { return postId; }
public void setPostId(Integer postId)
{
this.postId = postId;
}
public String getTitle() { return title; }
public void setTitle(String title)
{
this.title = title;
}
}
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
@Controller
public class PostController {
@Autowired
PostService service;
@GetMapping("/posts/{id}")
public @ResponseBody Post findById(@PathVariable("id") Integer postId) {
return service.findById(postId);
}
@PostMapping("/updatepost")
public void updatePost(Post post) {
service.updatePost(post);
}
@DeleteMapping("/posts/{id}")
public void deleteById(@PathVariable("id") Integer postId) {
service.deleteById(postId);
}
}
Service class:
The two caching annotations used in the code are explained as follows:
@CachePut: Cached objects are copies of original objects inside the database and should be identical to them. When the original object changes, then the cached object should be updated. This is done using the @CachePut annotation and is applied over the method that performs update operation.
@CacheEvict: This annotation is used to indicate a remote operation of the data from the cache and is applied to the method that deletes an object from the database
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class PostService {
@Cacheable("posts")
public Post findById(Integer postId) {
System.out.println("Fetching Post");
return new Post(postId, "Demo post");
}
@CachePut("posts")
public void updatePost(Post post) {
// update post
}
@CacheEvict("posts")
public void deleteById(Integer postId) {
// delete post
}
}
In order to test that caching is working, we have to hit URL, http://localhost:8080/posts/1, and look at the console. It should print the following output:
Output: Fetching Post
https://www.geeksforgeeks.org/spring-boot-ehcaching/