You are here
Home > Redis >

How to implement Redis Cache in Spring Boot Application?

How to implement Redis Cache in Spring Boot Application?Many a time, we all come to a phase when our application does not perform well as it is expected to. Apart from several other solutions, we also look for a caching technique to make DB calls faster. In order to make it possible, we have Redis Cache technique in place. Redis cache helps us by minimizing the number of network calls while accessing tha data from DB. Needless to say, our topic of discussion in this article is ‘How to implement Redis Cache in Spring Boot Application’.

Spring Boot supports this feature via the dependency ‘Spring Data Redis’. In addition, we need to download Redis Server to make Redis Cache functional in the Spring Boot Application. Moreover, apart from Cache, Redis can also be used as a database and Message Broker. However, in  a real time application, Redis is popular for a Cache Manager as compared to database & Message Broker. Let’s start discussing the topic of our  article ‘How to implement Redis Cache in Spring Boot Application’ and its related concepts.

If you want to learn CRUD operation using Redis DB, please visit our internal article on ‘Spring Boot Redis CRUD Example‘.

What can you expect from this Article?

Once you go through the complete article, you will be able to answer the following questions:

1) What is Redis?
2) What is Redis Used for?
3) What is Redis Cache?
4) What is the advantage of using Redis Cache in your application?
5) How does the Redis Cache work in the Application?
6) What is Redis Database?
7) What is Redis Server?
8) How to download Redis Server?
9) What are the important annotations to enable Redis Cache in the Application?
10) How to write a REST application in Spring Boot?
11) How to implement Redis Cache in Spring Boot?
12) In the end, How to test the application after implementing Redis Cache?

What is Redis?

Redis is an open source(BSD licensed) in-memory remote data structure store(database) that offers high performance, replication, and a unique data model. The full form of Redis is Remote Directory Server. Moreover, we can use it in multiple forms. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams.

You can use Redis from most programming languages. Redis is written in ANSI C and works in most POSIX systems like Linux, *BSD, and OS X, without external dependencies. Linux and OS X are the two operating systems where Redis is developed and tested the most.

What is Redis Used for?

We can use Redis in the following forms.

1) In-Memory Database : As an In-Memory database, We will get some empty memory to perform database operations. Moreover, it acts as No-SQL database and there are No Tables, No Sequences, No Joins concept. We can store data in the form of String, Hash Operations***, List, Set etc. In-built services will be available.
2) Cache : We can also use Redis as a Cache to increase our application performance.
3) Message Broker(MQ) : Another use of Redis is as a Message Broker.

In real time application, Redis is popular for a Cache Manager as compared to database. As a cache manager, It reduces network calls and improves the performance of an application.

What is Redis Cache?

Redis Cache is nothing but a Cache Management feature offered by Redis. Redis is normally used as a cache to store repeatedly accessed data in memory so that the user can feel the better performance of the application. The Redis Cache offers varous features like how long you want to keep data, and which data to remove first, and some other bright caching models.

What is the advantage of using Redis Cache in your application?

Like any other Caching Technique, Redis Cache also minimizes the number of network calls made by your application, which in return improves  performance of the application as a whole. One request from an application to the DB is similar to one network call.

How does the Redis Cache work in the Application?

When we perform a DB retrieve operation via an Application, the Redis Cache stores the result in it’s cache. Further, when we perform the same retrieve operation, it returns the result from the cache itself and ignore the second call to database. Similarly, when we perform a DB update operation, the Redis Cache also updated the result in its cache. Needless to say, for delete operation also it deleted the data from the cache accordingly. In this way, there are no chances of getting incorrect data.

What is Redis Database?

Redis Database is an in-memory database that persists on disk. It means when we use Redis Database, we occupy a memory on the disk to use as a Database. The data model is key-value, but many several kind of values are supported such as Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps etc.

What is Redis Server?

The full form of Redis is REmote DIctionary Server. When we use Redis in any form such as database, cache or Message Broker, we need to download a Redis Server in our system. People in the industry just call it Redis Server.

How to download Redis Server?

1) Visit any of the link below to download Redis
Download Redis Server  :  version 3.2.100
Download Redis Server  :  version 5.0.10
2) Click on Redis-x64-5.0.10.zip and extract it to a folder
3) Under folder ‘Redis-x64-5.0.10’, you will find redis-server.exe
4) In order to start Redis Server, double click on ‘redis-server.exe’ to start Redis Server

What are the important annotations to enable Redis Cache in the Application?

Generally, there are four important annotations that we apply to implement Redis Cache feature in ur application. They are as below:

@EnableCaching 

We apply this annotation at the main class (starter class) of our application in order to tell Spring Container that we need Caching feature in our application.

@Cacheable 

@Cacheable is used to fetch(retrieve) data from the DB to application and store in Redis Cache. We apply it on the methods that get (retrieve) data from DB.

@CachePut 

We use @CachePut in order to update data in the Redis Cache while there is any update of data in DB. We apply it on the methods that make modifications in DB.

@CacheEvict 

We use @CachePut in order to remove data in the Redis Cache while there is any removal of data in DB. We apply it on the methods that delete data from DB.

How to implement Redis Cache in Spring Boot Application?

In order to implenet Redis Cache using Spring Boot, we need to create one small application that will have CRUD operations in place. Then we will apply Redis Cache feature in Retrieve, Update and Delete Operations. However, we should noe apply Cache feature in a Create operation as we will not get any benefit of it. Let’s start working on ‘How to implement Redis Cache in Spring Boot?’ step by step as below:

Details of Use-case 

We will create a CRUD application using REST. Here, let’s assume our entity class is Invoice.java. In order to create a complete REST Application, we will have Controller, Service & Repository layers as per industry best practices. Once we complete developing the Invoice REST Application, we will further apply annotations on certain methods to get benefits of Redis Cache. This is the step by step approach to implement the Redis Cache in our application. However, we are going to provide the complete code of each file.

Step#1: Create a new Spring Boot Starter Project using STS

Let’s create a Spring Boot Starter project using STS. While creating Starter Project select ‘Spring Web’, ‘Spring Data JPA’, ‘MySQL Driver’, ‘Spring Data Redis’, ‘Lombok’, and ‘Sprong Boot DevTools’ as starter project dependencies. Even If you don’t know how to create a Spring Boot Starter Project, Kindly visit our Internal Link. Even, if you are new to ‘Lombok’, kindly visit ‘How to configure Lombok‘ and to know all about it in detail.

Step#2: Update application.properties

The application.properties will be as below:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/rediscachetest
spring.datasource.username=root
spring.datasource.password=****

spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

spring.cache.type=redis
spring.cache.redis.cache-null-values=true
#spring.cache.redis.time-to-live=40000

Step#3: Add annotation @EnableCaching at starter class

The annotation @EnableCaching is required to get benefits of Caching Feature.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class RedisAsaCacheWithSpringBootApplication {

   public static void main(String[] args) {
      SpringApplication.run(RedisAsaCacheWithSpringBootApplication.class, args);
   }
}

Step#4: Create an Entity class as Invoice.java

Below code represents the entity class with Lombok Annotations on it. Additionally, make sure to create one serialVersionUID.

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Invoice implements Serializable{

   private static final long serialVersionUID = -4439114469417994311L;

   @Id
   @GeneratedValue
   private Integer invId;
   private String invName;
   private Double invAmount;
}

Step#5: Create a Repository Interface as InvoiceRepository.java

Now, lets create a Repository Interface as InvoiceRepository.java which will extend JpaRepository<Invoice, Integer> as below.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.dev.springboot.redis.model.Invoice;

@Repository
public interface InvoiceRepository extends JpaRepository<Invoice, Integer> {

}

Step#6: Create a Custom Exception calss as InvoiceNotFoundException.java

This class is just to handle Exceptions in a proper way.

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class InvoiceNotFoundException extends RuntimeException {

   private static final long serialVersionUID = 7428051251365675318L;

   public InvoiceNotFoundException(String message) {
      super(message);
   }
}

Step#7 & 8: Create Service Interface & Impl class as InvoiceService.java & InvoiceServiceImpl.java

In order to develop a service layer, we will have a service interface & an implementation class of it as InvoiceService.java and InvoiceServiceImpl.java respectively as below. The InvoiceServiceImpl.java is the class where we need to keep our focus on. Moreover, this is the place where we apply Caching Mechanism offerred by Redis.

import com.dev.springboot.redis.model.Invoice;
import java.util.List;

public interface InvoiceService {

    public Invoice saveInvoice(Invoice inv);
    public Invoice updateInvoice(Invoice inv, Integer invId);
    public void deleteInvoice(Integer invId);
    public Invoice getOneInvoice(Integer invId);
    public List<Invoice> getAllInvoices();
}

 

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.dev.springboot.redis.exception.InvoiceNotFoundException;
import com.dev.springboot.redis.model.Invoice;
import com.dev.springboot.redis.repo.InvoiceRepository;

@Service
public class InvoiceServiceImpl implements InvoiceService {

    @Autowired
    private InvoiceRepository invoiceRepo;

    @Override
    public Invoice saveInvoice(Invoice inv) {

        return invoiceRepo.save(inv);
    }

    @Override
    @CachePut(value="Invoice", key="#invId")
    public Invoice updateInvoice(Invoice inv, Integer invId) {
       Invoice invoice = invoiceRepo.findById(invId)
            .orElseThrow(() -> new InvoiceNotFoundException("Invoice Not Found"));
       invoice.setInvAmount(inv.getInvAmount());
       invoice.setInvName(inv.getInvName());
       return invoiceRepo.save(invoice);
    }

    @Override
    @CacheEvict(value="Invoice", key="#invId")
    // @CacheEvict(value="Invoice", allEntries=true) //in case there are multiple entires to delete
    public void deleteInvoice(Integer invId) {
       Invoice invoice = invoiceRepo.findById(invId)
           .orElseThrow(() -> new InvoiceNotFoundException("Invoice Not Found"));
       invoiceRepo.delete(invoice);
    }

    @Override
    @Cacheable(value="Invoice", key="#invId")
    public Invoice getOneInvoice(Integer invId) {
       Invoice invoice = invoiceRepo.findById(invId)
         .orElseThrow(() -> new InvoiceNotFoundException("Invoice Not Found"));
       return invoice;
    }

    @Override
    @Cacheable(value="Invoice")
    public List<Invoice> getAllInvoices() {
       return invoiceRepo.findAll();
    }
}

Step#9: Create RestController class as InvoiceRestController.java 

This RestController will have end-points to make REST calls and get results.

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.dev.springboot.redis.model.Invoice;
import com.dev.springboot.redis.service.InvoiceService;

@RestController
@RequestMapping("/invoice")
public class InvoiceController {

    @Autowired
    InvoiceService invoiceService;

    @PostMapping("/saveInv")
    public Invoice saveInvoice(@RequestBody Invoice inv) {
       return invoiceService.saveInvoice(inv);
    }

    @GetMapping("/allInv") 
    public ResponseEntity<List<Invoice>> getAllInvoices(){
       return ResponseEntity.ok(invoiceService.getAllInvoices());
    }

    @GetMapping("/getOne/{id}")
    public Invoice getOneInvoice(@PathVariable Integer id) {
       return invoiceService.getOneInvoice(id);
    }

    @PutMapping("/modify/{id}")
    public Invoice updateInvoice(@RequestBody Invoice inv, @PathVariable Integer id) {
       return invoiceService.updateInvoice(inv, id);
    }

    @DeleteMapping("/delete/{id}")
    public String deleteInvoice(@PathVariable Integer id) {
       invoiceService.deleteInvoice(id);
       return "Employee with id: "+id+ " Deleted !";
    }
}

How to test the application after implementing Redis Cache?

1) Start Redis Server.
2) Start your Spring Boot Application.
3) Make a Rest Call using any REST client on operations which are get, update & delete. You can use any REST client such as any User Interface, RestTemplate or Postman etc. However, we have used Postman just to test the functionality.
4) When you call an operation for the first time, you should see a DB query in the console.
5) If you call the same operation for the second time, you should not see the DB query in the console. If it is, you have successfully applied the Redis Cache.

Conclusion

After going through all the theoretical & example part of ‘How to implement Redis Cache in Spring Boot Application?’, finally, we should be able to implement Redis Cache in a Spring Boot Application. Similarly, we expect from you to further extend these examples and implement them in your project accordingly. I hope you might be convinced by the article ‘How to implement Redis Cache in Spring Boot Application?’. In addition, If there is any update in the future, we will also update the article accordingly. Moreover, Feel free to provide your comments in the comments section below.

close

Leave a Reply

Top