Sunday, March 19, 2023

Spring Data Redis

Introduction:

The Spring Data Redis (SDR) framework makes it easy to write Spring applications that use the Redis key-value store by eliminating the redundant tasks and boilerplate code required for interacting with the store through Spring’s excellent infrastructure support.

Redis Requirements

Spring Redis requires Redis 2.6 or above and Spring Data Redis integrates with Lettuce and Jedis, two popular open-source Java libraries for Redis.




Configuring the Lettuce Connector


<!--Lettuce -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.3.RELEASE</version>
</dependency>

Create a new Lettuce connection factory:
@Configuration
public class AppConfig {

@Bean
public LettuceConnectionFactory redisConnectionFactory() {

return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379));
}
}

Configuring the Jedis Connector

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>

Create a new Jedis connection factory:
@Configuration
public class AppConfig {

@Bean
public JedisConnectionFactory redisConnectionFactory() {

RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("localhost", 6379);
return new JedisConnectionFactory(config);
}
}

Simple configuration in application.yaml

# Server config
server:
port: 9000

# Redis Config
spring:
redis:
host: 127.0.0.1
port: 6379

Overall, Lettuce's event-driven, non-blocking architecture and thread-safety make it a good choice for high-concurrency environments, whereas Jedis' simplicity and ease of use make it a good choice for simpler applications. However, the choice between Lettuce and Jedis ultimately depends on the specific requirements of the application and the environment in which it will be deployed.

RedisTemplate

The template is, in fact, the central class of the Redis module, due to its rich feature set. The template offers a high-level abstraction for Redis interactions. 

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}


Use the RedisTemplate to store and retrieve values
private final RedisTemplate<String, Object> redisTemplate;

public My_class(RedisTemplate<String, Object> redisTemplate) {
this.userRepository = userRepository;
}

The opsForValue() method of the RedisTemplate to interact with Redis as a key-value store.

Technology

  • Spring Boot 3.0.4
  • Spring Data Redis 3.0.4
  • H2 Database
  • Java 17
  • Docker
  • Maven 
  • IntelliJ IDEA


Downloading and installing Redis

docker run --name my-redis -p 6379:6379 -d redis

Configuring Redis Cache Spring Boot

Use the @EnableCaching annotation on Spring Boot main class:


@SpringBootApplication
@EnableCaching
public class SpringBootRedisCacheApplication implements CommandLineRunner {

private final Logger LOG = LoggerFactory.getLogger(getClass());

private final PersonRepository personRepository;

public SpringBootRedisCacheApplication(PersonRepository personRepository) {
this.personRepository = personRepository;
}

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

@Override
public void run(String... args) throws Exception {

//Populating embedded database here
LOG.info("Current user count is {}.", personRepository.count());
Person p1 = new Person("p1","test", 25);
Person p2 = new Person("p2", "test",28);
Person p3 = new Person("p3", "test", 60);

personRepository.save(p1);
personRepository.save(p2);
personRepository.save(p3);
LOG.info("Data: {}.", personRepository.findAll());

}
}

Repository

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}

Controller

@Cacheable annotation:

  • @GetMapping("/{personByRedisTemplate}") using RedisTemplate, retrieve the last person id.
  • @GetMapping("/{personId}") save in RedisTemplate and method will put a person into a cache named as ‘persons’, identifies that person by the key as ‘personId’ and age < 26.
  •  @CachePut updating Cache.
  • @CacheEvict clearing Cache.

@RestController
public class PersonController {

private final RedisTemplate<String, Object> redisTemplate;

private final PersonRepository PersonRepository;

public PersonController(RedisTemplate<String, Object> redisTemplate, PersonRepository PersonRepository) {
this.redisTemplate = redisTemplate;
this.PersonRepository = PersonRepository;
}

@GetMapping("/personByRedisTemplate")
public Person getPersonByRedisTemplate(){
var person = (Person) redisTemplate.opsForValue().get("personId");
return person!=null?person:null;
}

@Cacheable(value = "persons", key = "#personId", unless = "#result.age < 29")
@GetMapping("/{personId}")
public Person getPerson(@PathVariable Long personId) {

var person = PersonRepository.findById(personId).get();
redisTemplate.opsForValue().set("personId", person);
return person;

}

@CachePut(value = "persons", key = "#person.id")
@PutMapping("/update")
public Person updatePersonByID(@RequestBody Person person) {
PersonRepository.save(person);
return person;
}

@CacheEvict(value = "persons", allEntries=true)
@DeleteMapping("/{personId}")
public void deletePersonByID(@PathVariable Long personId) {
PersonRepository.delete(new Person(personId));
}

}


Run & Test


Run Spring Boot application with command: mvn spring-boot:run. by console, IntelliJ etc.

By curl request or Postman.
  • curl http://127.0.0.1:9000/1
  • curl http://127.0.0.1:9000/personByRedisTemplate
  • curl --location --request PUT 'http://127.0.0.1:9000/update' \ --header 'Content-Type: application/json' \ --data '{"id" : 3, "firstname" : "p4", "lastname" : "test", "age" : 30 }'
  • curl --location --request DELETE 'http://127.0.0.1:9000/3'




Multiple Data Sources in Spring Boot 3 with Java 21

  In this blog post, we'll explore the configuration and setup for a Spring Boot 3 application with Java 21 that uses multiple data sour...