Spring Boot in-memory Caching
with Simple provider
Caching is really a simple and straightforward technique to increase the performance of an application by minimizing the number of database hits. In this article, we will be looking at the cache abstraction mechanism in the Spring Boot framework. Actually, it's annotation-based and easy-to-use. 😊 Spring Boot supports a variety of Cache Providers like,
· Generic
· EhCache
· Hazelcast
· Couchbase
· Redis
· Caffeine
· Simple
But in this article, we will be discussing about the Simple provider, which is the default one. Actually, it is nothing but a ConcurrentHashMap. 😄 Your frequently used data will be saved as key-value pairs. Therefore, you don’t need to fetch those data from the database frequently. Access data from this in-memory ConcurrentHashMap (cache) is always faster than fetching data from the actual database.
What data should be cached?
- The data that do not change frequently.
- The data that is needed to read frequently.
Okay, now let’s implement this Caching mechanism in a Spring Boot application.
Spring Boot Caching in Action
First, we need to initialize a Spring Boot project and add the following dependency to our pom.xml file.
@EnableCaching
To enable caching in our application, we need to add @EnableCaching annotation to our Spring Boot Application class. It’s a class-level annotation. 😊
Cool! We have enabled caching mechanism in our application and now we can start the implementations. We are going to create a simple Student Management application with all the CRUD operations.
First, let's create our Student model class and the StudentRepository interface by extending JpaRepository. Just like this. 👇
Here, I’m using Lombok to auto-generate Constructors, Setters and Getters.
Now we can move to implement our Service class. That’s where the fun begins 😊
As our first step let's create a service to add a new Student to the database.
The addNewStudent() method is supposed to insert a new Student record into the database. Normally, we don’t need to cache this kind of behavior. Why? Because we are not read anything using this method, we are inserting a new record. Right? 😉 But remember, we can store our Student object in a ConcurrentHashMap when returning the saved object from the method. You will be able to do that once you understand the underlying concept behind this caching mechanism. 😃
@Cacheable
Next, let’s try to retrieve a Student object from the database.
Here, I have used Thread.sleep() method to simulate the backend delay.
What is the use of @Cacheable annotation?
Here, we are notifying the Spring Boot framework to store the returning value of the findStudent() method inside a ConcurrentHashMap which named as studentCache
with studentId
as it’s key. In simple terms, Spring Boot uses the specified parameter of the method as the key and the return value as the value in the cache.
What happens when the findStudent() method is called?
When the findStudent() method called for the first time, Spring Boot will check if the value is present inside the ConcurrentHashMap with the given key. At the first time value will not be there, and it will execute the findStudent() method and return the value after querying the database. While it’s returning, the value or the Student object, in this case, will be stored in the ConcurrentHashMap as a key-value pair.
When the findStudent() method called for the second time, again, Spring Boot will check if the value is present in the ConcurrentHashMap with the given key. This time value or the Student object is there with the same key. Therefore findStudent() method will not be executed and the value will be returned from the ConcurrentHashMap.
What if we want to Update or Delete an entry from the database?
It’s simple. Let’s take the Update first.
@CachePut
We need to create a service to update an existing database record. Look 👇
Look at the @CachePut annotation on top of the updateStudent() method. Here we are referring to the same ConcurrentHashMap which is studentCache
. And we are accessing the value with student.studentId
as the key. Here, the updateStudent() method will be executed and it will update the matching entry in the database and @CachePut annotation will update the matching entry from the ConcurrentHashMap at the same time.
@CacheEvict
Assume we want to delete an entry from the database as well as from the Cache. In that case, we can simply use @CacheEvict annotation.
Again, we are referring to the same ConcurrentHashMap which is studentCache
. And we are accessing the value with studentId
as the key. As earlier, deleteStudent() method will be executed and it will delete the matching entry from the database and at the same time, @CacheEvict annotation will remove the matching entry from the ConcurrentHashMap.
So, here you can see @CachePut and @CacheEvict annotations will help us to keep our Cache or the ConcurrentHashMap up to date. Just to know these #student.studentId
and #studentId
syntaxes are coming from Spring Expression Language. 😃
Okay, we have implemented the caching mechanism. 😊
As our final step, let’s create the RestController. It’s our usual controller and there is nothing special in it. Look 👇
Cool!!! We have completed the implementation of our simple Student Management application. Now let's see how the caching mechanism increased the performance of our application.
Here you can see the first request took 5.09 seconds to respond back. But the second request took only 8 milliseconds to respond to the same request. It’s because with the first request Spring Boot framework stored that returning value inside the Cache that we have implemented. When the second request hits Spring Boot framework returned the value from the cache, not from the database.
When comparing 5.09 seconds with 8 milliseconds we can see that there is a huge difference between those two response times. Here you can see with a proper caching mechanism we can drastically increase the performance of an application.
In this article, we have discussed the very basics of the Spring Boot in-memory caching mechanism. You can find the complete source code from here. Hope you learned something valuable from this article. Thanks for reading and Cheers for now!!!
Happy Coding!!!