Spring Boot Redis Cache

author-image  By Dhiraj,   29 June, 2019 0K

In this tutorial, we will be discussing the integration of Redis cache with Spring Boot by developing a CRUD operation example using Jedis and spring boot starter data redis. In the tutorial, we will explore 2 different ways to perform CRUD operations. First, we will be defining our custom RedisTemplate and use HashOperations to perform get and put operations on Redis server. Next, we will be using @Cacheable annotation to enable implicit caching mechanism by Spring Boot and upon cache miss, the lookup will be done in the DB with spring boot starter data jpa.

What is Redis

Redis is an in-memory data structure store implementing a distributed, in-memory key-value database with optional durability. It can be used as a database, cache or as a message broker. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, HyperLogLogs, bitmaps, streams, and spatial indexes.

Redis is very fast as it is written in ANSI C and works in most POSIX systems like Linux, *BSD, OS X without external dependencies. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence.

Redis is best suited for caching in a distributed system and in this age of microservices Redis cache is very useful.

Setting up Redis Server Locally

First of all, we need to have Redis server running and we should have the connection properties such as host, port, password, etc. For this example, I have installed Redis server on my local machine. You can follow my Redis server installation on Windows and Mac tutorial to setup Redis server locally.

Once, the Redis server setup is done you can actually run below commands from the redis-cli.

redis-cli-command-screenshot

Spring Boot Redis Cache Maven Configuration

We can use spring-boot-starter-data-redis maven artifact provided by Spring boot to integrate Redis with spring boot project. Below are the maven dependencies that we require for the integration.

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-redis</artifactId>
	</dependency>
	<dependency>
		<groupId>redis.clients</groupId>
		<artifactId>jedis</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>

Jedis is a blazingly small and sane Redis java client.

spring-boot-starter-data-redis provides Redis based operations and integrations similar to spring data.

spring-boot-starter-web is for exposing the REST endpoints in order to test our CRUD operations.

Spring Boot Redis Configuration

We require to define 2 Spring beans, JedisConnectionFactory and RedisTemplate to configure Redis with Spring Boot. Below are the beans definition:

@Configuration
public class BeanConfig {

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration("localhost", 6379);
        redisStandaloneConfiguration.setPassword(RedisPassword.of("password"));
        return new JedisConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public RedisTemplate redisTemplate() {
        RedisTemplate template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        return template;
    }
}

JedisConnectionFactory setHostName is deprecated and hence we require to use RedisStandaloneConfiguration to configure JedisConnectionFactory with our custom hostname, port and password.

We can also provide these configurations via properties file configuration. Below are the application.properties file entries.

spring.redis.host=127.0.0.1 
spring.redis.password=password
spring.redis.port=6379

We can define connection pool related configurations too in the above properties file.

Spring Boot Redis Crud Operations

Defining Redis Repository

Let us define our Redis repository class that will have all the implementations for put, get, delete, etc. We have injected RedisTemplate and HashOperations here.

@Repository
public class RedisUserRepository {

    private HashOperations hashOperations;

    private RedisTemplate redisTemplate;

    public RedisUserRepository(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
        this.hashOperations = this.redisTemplate.opsForHash();
    }
...
}

This implementation is useful when we do not require any persistent storage of any object in DB. There are many use cases which requires in-memoery calculations and operations and store those results for specific period. We will discuss about the persistent stoarge and cache hit and cache miss related topics in later sections below.

Redis PUT Operation

PUT operation sets the value of the supplied hashkey. Below is the implementation that adds user object to the Redis cache.

public void save(User user) {
        hashOperations.put("USER", user.getId(), user);
}

Redis GET Operation

GET operation fetches the value for given hashKey from hash at key.

public User findById(String id){
        return (User) hashOperations.get("USER", id);
    }

Redis DELETE Operation

DELETE operation removes given key from the cache. There is also an option to remove a value of supplied hash key from the key.

public User findById(String id){
        return (User) hashOperations.get("USER", id);
    }

Redis VALUES Operation

VALUES operation retrieves all the values from the key. Below implementation returns a list object but there are operations to return key value pairs.

public User findById(String id){
        return (User) hashOperations.get("USER", id);
    }

Putting it All Together

@Repository
public class RedisUserRepository {

    private HashOperations hashOperations;

    private RedisTemplate redisTemplate;

    public RedisUserRepository(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
        this.hashOperations = this.redisTemplate.opsForHash();
    }

    public void save(User user){
        hashOperations.put("USER", user.getId(), user);
    }
    public List findAll(){
        return hashOperations.values("USER");
    }

    public User findById(String id){
        return (User) hashOperations.get("USER", id);
    }

    public void update(User user){
        save(user);
    }

    public void delete(String id){
        hashOperations.delete("USER", id);
    }

}

Controller Implementation

Below is the controller implementation for testing all the CRUD operations.

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private RedisUserRepository userRepository;

    @PostMapping
    public User save(@RequestBody User user){
        userRepository.save(user);
        return user;
    }

    @GetMapping
    public List list(){
        return userRepository.findAll();
    }

    @GetMapping("/{id}")
    public User getUser(@PathVariable String id){
        return userRepository.findById(id);
    }

    @PutMapping
    public User update(@RequestBody User user){
        userRepository.update(user);
        return user;
    }

    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable String id){
        userRepository.delete(id);
        return id;
    }
}

Testing the Spring Boot Redis Cache

Below are the endpoints that can be used to test our above implementation.

Redis PUT Operation Test

Method : POST
URL : http://localhost:8080/users
Body : 
{
	"name":"dhirjjaj",
	"age": 23,
	"id":"1234"
}

Redis GET Operation Test

Method : GET
URL : http://localhost:8080/users

Redis UPDATE Operation Test

HTTP Method : PUT
URL : http://localhost:8080/users
Body : 
{
	"name":"dhirjjaj",
	"age": 23,
	"id":"1234"
}

Redis DELETE Operation Test

HTTP Method : DELETE
URL : http://localhost:8080/users/1234

Spring Boot Data Redis Implementation

In the above implementation, Redis itself is acting as a store house for our user entity. Above use case is useful when we don't require any persistent storage. For a persistent storage, we need to have a DB and upon a cache miss, our integration should perform a looup in the DB. For this we need to have spring-boot-starter-data-jpa module from spring boot.

Let us not discuss this integration here as it is a seperate topic of integration of spring data with spring boot. Here, we assume we have already spring data integrated and repository implementation is done. The complete implementation of spring boot data can be found here.

Hence, let us directly implement our service class that will have caching enabled with method level annotation @Caheable and upon cache miss a DB lookup is made.

Spring Boot Data Repository

Once, we have below dependencies added in the pom, we can define our repository.

ltdependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

@Cacheable in Spring Boot Data Redis

The @Cacheable annotation can be applied at method level. When applied at method level, then the annotated method’s return value is cached with key as the method parameter. You can use other params such as cacheName, cacheManager, conditions with it.

You need to annotate your spring boot main class with @EnableCaching to enable caching.

Below is an example of using @Cacheable. If the cache is missed then the method will be executed and it will fetch user from the repository and the same will be cached in Redis.

@Cacheable(value = "users", key = "#userId")
public User getUser(String userId) {
  return userRepository.findOne(Long.valueOf(userId));
}

Conclusion

In this tutorial, we will discussed the integration of Redis cache with Spring Boot by developing a CRUD operation example using Jedis and spring boot starter data redis.

If You Appreciate This, You Can Consider:

  • Like us at: Facebook or follow us at Twitter
  • Share this article on social media or with your teammates.
  • We are thankful for your never ending support.

About The Author

author-image

Further Reading on Spring Boot

1. Spring Boot Mongodb Crud

2. Spring Boot Mongodb Configuration

3. Spring Boot Angular Captcha

4. Spring Boot Async Task Executor

5. Spring Ehcache Cacheable Example Javaconfig

6. Spring Jms Activemq Integration Example

7. Spring Mvc Angularjs Integration Example