Cache results for pagination to improve performance
In modern application, caching is the integral part. It can increase performance, scalability and availability of application. Main idea is to reduce latency and make application faster. When no of requests are increased, caching will be really useful for accommodating whole requests.
Caching
Caching is a technique to increase application performance. Cache can be in-memory, database, or a server depending upon implementation.
Caching makes data access faster since the data is fetched from the database or data store for the first request. For subsequent requests, data is fetched from cache and the database or data store is not accessed.
Application looks for required data in cache first and does not directly hit the database or actual data store. If data is not found in cache then it accesses a database or data store.
Why cache for pagination ?
We know pagination is technique of splitting a list of multiple records into sub-list. Small portion of data is displayed at a time so that user can consume information more easily and conveniently. In this regard, the complete list can be fetched repeatedly from datastore or we can fetch it once and store in cache to avoid cost of data access.
In this article, we will touch upon how to configure cache in micro-services and implement pagination use case.
Spring boot cache annotations
Following are the annotations that are needed to add caching support to Spring boot application.
@EnableCaching
This annotation is used to inform Spring boot that we want to enable caching in this application. This annotation is applied over Spring boot main class or Spring configuration class. Spring provides one concurrent hashmap as default cache, but we can override Cache Manager to register external cache providers as well.
@Cacheable
This annotation is used to inform Spring boot which objects we want to cache. This annotation can be applied over a method or class.
When the annotation is applied over a method then the return value of the method is cached by Spring.
When annotation is applied over the class then caching behavior is added to all the methods in class and return values from all methods are cached.
@CachePut
This annotation is used to inform Spring boot to update cached objects. Cached objects are copies of original objects in the database and always should be identical to them. When original objects get changed, cached objects should also be changed. This is done by using @CachePut annotation. This method ensures that data is fetched from the database or data store and the result is updated in cache.
@CacheEvict
This annotation is used to indicate a removal operation of data from cache. This annotation is applied over the method that performs delete operation in the database.
Caching with micro-service using Spring Boot
In this example, we will see how to enable default caching in spring boot project and how application performance improves on the repeated calls to the same method. Also, we will see how paginations works with cache.
Create Spring boot project :
Create one simple spring boot project with spring boot web dependency for hosting on a web server.
To do this go to https://start.spring.io/ and provide maven coordinates and select dependencies. Click on the Generate button. It will download a zip file containing the skeleton project. Unzip the file and import in IDE. Perform maven clean install to download initial dependencies.
Main Class :
Domain Class :
Controller Class :
Service Interface :-
Service Impl Class :
Let’s test a few scenarios to see cache in action.
Case 1: multiple search requests with pagination
We will pass the department id in the url and page number in the header. We have defined page size as 2 in code (DepartmentServiceImpl.java)
lets hit http://localhost:8080/department/1 . It should print :
Controller>> searching by id 1
### Fetching Student from data store #####
When we hit the url again and again then it should print only
Controller>> searching by id 1
This means the service method is invoked first time only and after that cache has provided the result. We can see in the screenshot that the first time it took 108ms to provide a response and the second time onwards it is taking only 10ms. In this example , we are accessing the data from the map and we can observe 10 times less time in request execution. When we have a lot of data from a database or another rest service, there is a lot of performance improvement.
Now if we change the page number, data will be fetched from the cache and we can see it took only 10ms to display the data.
Now if we change the id then the method will be invoked for the first time.
Case 2 : Update data and search
When we update the data then data should be updated in cache as well. @CachePut ensures to get the data from the data store or database and put the updated result in the cache. So when a request comes to fetch data then cache provides updated results.
Note:- Record will be added in the last of the map so we need to update pageNo in request to see results.
To test this , lets hit http://localhost:8080/updateDepartment/1
Now, let’s hit again get request.
Case 3 :- Delete the data and search
When we delete the data, it should be deleted from the cache as well. @CacheEvict removes the data from cache and when there is a request to get data then there is no result.
This is one of the best way to implement cache with pagination, on the similar path we can implement filter and sorting as well.