🏠CachingSpring Boot Redis Cache

Spring Boot Redis Cache

Let’s learn how to implement redis as a cache store in spring boot with an example.

Previously, We discussed how to enable caching implementation in Spring Boot using an in-memory cache manager. But, there were few drawbacks to that approach. This is where the Redis cache store comes into the picture.

Introduction

Redis is a high performance datastore with high read/write throughput. This is why it is a perfect candidate to storing cache and session information.

Setup Local Server for Redis

The best way to setup server in local is to use docker. In this case, I’m using redis along with redis-commander GUI for redis.

version: '3' services: redis: container_name: redis hostname: redis image: redis ports: - "6379:6379" redis-commander: container_name: redis-commander hostname: redis-commander image: rediscommander/redis-commander:latest restart: always environment: - REDIS_HOSTS=local:redis:6379 ports: - "8081:8081"
Code language: JavaScript (javascript)

The above step is only for testing things locally. For production, please follow official Redis documentation for the server installation.

Run the following command for starting the containers.

docker-compose docker-compose.yml up -d
Code language: CSS (css)

Once the docker container is up, You can view redis commander at http://localhost:8081.

Add redis dependencies

Like always, Spring boot makes things easier with the help of sophisticated starter dependencies. All you have to do is to add the redis starter.

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Code language: HTML, XML (xml)

Add appropriate settings for the redis configuration. You can skip the following if you are using redis locally.

spring.redis.host=localhost spring.redis.port=6379
Code language: Properties (properties)

In production you may need to add spring.redis.username and spring.redis.password based on your server.

Enable Caching

To enable caching support in Spring boot , first you need to annotate the main class with @EnableCaching.

@EnableCaching @SpringBootApplication public class SpringBootRedisCacheExampleApplication { public static void main(String[] args) { SpringApplication.run(SpringBootRedisCacheExampleApplication.class, args); } }
Code language: Java (java)

Add @Cacheable annotation

Find a long running method and annotate it with @Cacheable. This annotation takes a value which is the cache name. And the key is an unique object to lookup the value in cache later.

@Cacheable(value = "items", key = "#id") public Item getItem(Integer id) { Item item = itemRepository.findById(id).orElseThrow(RuntimeException::new); logger.info("Loading data from DB {}", item); return item; }
Code language: Java (java)

In this case, We used Spring Expression Language(SpEL) to pass the argument value as key.

Add @CacheEvict annotation

Once cached, The values stay there indefinitely. Thus, the cache abstraction will never pick updated values from the database. For this reason, you should use @CacheEvict on update.

@CacheEvict(value = "items", key = "#id") public Item updateItem(Integer id, Item request) { Item item = getItem(id); item.setPrice(request.getPrice()); item.setProductName(request.getProductName()); return itemRepository.save(item); }
Code language: Java (java)

See Redis in Action

Once we start the application, The first request goes to the database. And the subsequent requests fetch data from redis cache store. We know this because,

  1. The logs says the records is from the database.
c.s.e.s.cache.service.ItemService:Loading data from DB Item{id=2,productName='Pants Large',price=21.99}
Code language: Java (java)
  1. When we open redis-commander, we can see that items cache containing entry with key 2 .These cached value is in the form of binary.

What about the cache evict? Let’s try updating item 2.

curl -X PUT \ http://localhost:8080/items/2 \ -H 'cache-control: no-cache' \ -H 'content-type: application/json' \ -d '{ "productName": "Pants Large", "price": 14.99 }' HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Sun, 13 Dec 2020 18:11:16 GMT {"id":2,"productName":"Pants Large","price":14.99}
Code language: Bash (bash)

As you see the cached value for key 2 is now gone. The next time a getItem call happens, the values will be cached again.

Caching between multiple application instances

As redis server runs outside the application, multiple application instances can share the same cache store. For example, Let’s run the same application again on different port 7070 (using —server.port=7070).

java -jar redis-demo.jar --server.port=7070
Code language: Bash (bash)

We can confirm that the second instance had successfully connected to the redis server by various means.

  1. By checking logs. There should not be any error when RedisAutoConfiguration takes place.
  2. By checking the client connections on the server. Click the local (redis:6379:0) element at the side nav of redis-commander, and it will give the server stats. In the results, find the value for Connected clients. The value should be 3. This is due to 2 connections from the application and 1 connection from the redis-commander itself.

Let’s call the API from application running on port 8080.

curl -X GET http://localhost:8080/items/2
Code language: Bash (bash)

This creates a cache entry in redis. Now try hitting server on 7070 for the same resource.

curl -X GET http://localhost:7070/items/2
Code language: Bash (bash)

The response is immediate and there is no logs that says the record is from the database.

Timeout for cached values

You can also specify how long the value can live in the cache store.

spring.cache.redis.time-to-live=5m
Code language: Access log (accesslog)

The above configuration will automatically evict any cached entry after 5 minutes.

Summary

To summarize, We learned how to use redis data store as cache for spring boot application. The code and the docker-compose.yml for this example is available in this github repository.

Also, if you like this article, You may find the following write-ups helpful.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *