Spring Boot – Redis

RMAG news

Docker Compose File

Here is the basic docker-compose redis configuration

services:
redis:
image: redis:latest
restart: always
ports:
– “6379:6379”
environment:
– REDIS_PASSWORD=my-password
– REDIS_PORT=6379
– REDIS_DATABASES=16

Maven dependency

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

Application yml file

spring:
cache:
type: redis
redis:
host: localhost
port: 6379

cache:
config:
entryTtl: 60
jwtToken:
entryTtl: 30

In application yml file, cache type and redis host, port informations are defined.
Redis config class

@Configuration
@EnableCaching
@Slf4j
public class RedisConfig {

@Value(“${spring.cache.redis.host}”)
private String redisHost;

@Value(“${spring.cache.redis.port}”)
private int redisPort;

@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort);
configuration.setPassword(“my-password”);
log.info(“Connected to : {} {}”, redisHost, redisPort);

return new LettuceConnectionFactory(configuration);
}

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.create(connectionFactory);
}

@Bean
public RedisTemplate<String, Object> redisTemplate(){
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new GenericToStringSerializer<Object>(Object.class));
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}

Working with cache annotations

To enable caching in your application, you can use the @EnableCaching annotation and then annotate methods that should be cached with @Cacheable, @CachePut, and @CacheEvict

@GetMapping(“/product/{id}”)
@Cacheable(value = “product”, key = “#id”)
public Product getProductById(@PathVariable long id) {…}

1. @Cacheable is employed to fetch data from the database, storing it in the cache. Upon future invocations, the method retrieves the cached value directly, eliminating the need to execute the method again.

The value attribute establishes a cache with a specific name, while the key attribute permits the use of Spring Expression Language to compute the key dynamically. Consequently, the method result is stored in the ‘product’ cache, where respective ‘product_id’ serves as the unique key. This approach optimizes caching by associating each result with a distinct key.

2. @CachePut is used to update data in the cache when there is any update in the source database.

@PutMapping(“/product/{id}”)
@CachePut(cacheNames = “product”, key = “#id”)
public Product editProduct(@PathVariable long id, @RequestBody Product product) {…}

3. @CacheEvict is used for removing stale or unused data from the cache.

@DeleteMapping(“/product/{id}”)
@CacheEvict(cacheNames = “product”, key = “#id”, beforeInvocation = true)
public String removeProductById(@PathVariable long id) {…}

We use cacheName and key to remove specific data from the cache. The beforeInvocation attribute allows us to control the eviction process, enabling us to choose whether the eviction should occur before or after the method execution.

@DeleteMapping(“/product/{id}”)
@CacheEvict(cacheNames = “product”, allEntries = true)
public String removeProductById(@PathVariable long id) {…}

Alternatively, all the data can also be removed for a given cache by using the allEntries attribute as true. The annotation allows us to clear data for multiple caches as well by providing multiple values as cacheName.

4. @Caching is used for multiple nested caching on the same method.

@PutMapping(“/{id}”)
@Caching(
evict = {@CacheEvict(value = “productList”, allEntries = true)},
put = {@CachePut(value = “product”, key = “#id”)}
)
public Product editProduct(@PathVariable long id, @RequestBody Product product) {…}

As Java doesn’t allow multiple annotations of the same type to be declared for a method, doing so will generate a compilation error. We can group different annotations into Caching, as shown.

5. @CacheConfig is used for centralized configuration.

@CacheConfig(cacheNames = “product”)
public class ProductController {…}

Working with RedisTemplate

You can use the RedisTemplate to interact with Redis. For example, to save data in Redis:

@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void saveData(String key, Object data) {
redisTemplate.opsForValue().set(key, data);
}

Retrieve data from Redis

public Object getData(String key) {
return redisTemplate.opsForValue().get(key);
}

Example service class for redis template

@Service
public class CacheTokenService {

private final StringRedisTemplate stringRedisTemplate;
private final RedisTemplate<String, Object> redisTemplate;

public CacheTokenService(StringRedisTemplate stringRedisTemplate, RedisTemplate<String, Object> redisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
this.redisTemplate = redisTemplate;
}

public void saveData(String key, Object data) {
redisTemplate.opsForValue().set(key, data);
}

public Object getData(String key) {
return redisTemplate.opsForValue().get(key);
}

public void cacheToken(String username, String token) {
stringRedisTemplate
.opsForValue()
.set(“token:” + username, token, Duration.ofMinutes(60));
}

public String getCachedToken(String username) {
// Retrieve the token from Redis cache
return stringRedisTemplate
.opsForValue()
.get(“token:” + username);
}

}

Redis GUI : RedisInsight

Download link : https://redis.io/insight/

Leave a Reply

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