1. /save - insert record in Redis database.
2. /findall - retrieve records from Redis database.
3. /find?id={id} - select a particular record from Redis database.
4. /uppercase?id={id} - update record in Redis to Uppercase.
5. /delete?id={id} - delete a record from Redis database.
Here is the high-level application’s architecture with Redis integration.
We can use Redis in-memory cache/database along with Microservices Architecture as below.
1. Redis as Configuration Server
2. Redis as a Message Broker
3. Redis as a Primary Database in case of multi-db usecases
Database Management systems store everything in second storage which makes read and write operations very slow. But Redis stores everything in primary memory (RAM) in form of key and value pairs which is very fast in reading and write of data. Also, In Redis, the key has to be a string but the value can be a string, list, set, sorted set, or hash.
Primary memory is limited (much lesser size and more expensive than secondary) therefore Redis cannot store large files or binary data. It can only store those small textual information which needs to be accessed, modified, and inserted at a very fast rate. If we try to write more data than available memory then we will receive errors.
Redis does not provide any mechanism for datastore backup and recovery. Therefore if there is any hard disk crash or any other kind of disaster then all data will be lost. You need to use some third-party server backup and recovery software to workaround it.
If you are using Redis in a replicated environment then there is no need for backup.
Follow the steps below:
Step 1: Download .zip or .msi file from Github
Go to https://github.com/microsoftarchive/redis/releases to download .zip or .msi file.
Note: The .zip file will may require you to add the environment variables manually while the .msi file is an installer and will add it automatically.
Java 8
Maven 3.5.0
Spring Boot 2.5.2
Eclipse
Spring Data Redis 2.5.2
Spring Boot Rest API
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-data-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-data-redis</name>
<description>Demo project for Spring Data - Redis</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application configurations file will be looked like as below.
#Application Configurations
server:
port: 8080
# Applicationn context name
servlet:
contextPath: /springbootdataredis
package com.the.basic.tech.info.redis;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringDataRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataRedisApplication.class, args);
}
}
package com.the.basic.tech.info.redis.config;
import java.time.Duration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
@Configuration
@ComponentScan("com.the.basic.tech.info.redis")
public class RedisConfig {
@Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName("localhost");
redisStandaloneConfiguration.setPort(6379);
redisStandaloneConfiguration.setDatabase(0);
// Note: Uncomment the below line if any password has been set
// redisStandaloneConfiguration.setPassword(RedisPassword.of("password"));
JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
jedisClientConfiguration.connectTimeout(Duration.ofSeconds(60));// 60s connection timeout
JedisConnectionFactory jedisConFactory = new JedisConnectionFactory(redisStandaloneConfiguration,
jedisClientConfiguration.build());
return jedisConFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
return template;
}
}
Here in this RestController we have exposed/implemented five Rest Interfaces for different operation in Redis.
package com.the.basic.tech.info.redis.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.the.basic.tech.info.redis.model.Customer;
import com.the.basic.tech.info.redis.repo.CustomerRepository;
@RestController
public class WebController {
@Autowired
private CustomerRepository customerRepository;
@RequestMapping("/save")
public String save() {
// save a single Customer
customerRepository.save(new Customer(1, "Jack", "Smith"));
customerRepository.save(new Customer(2, "Diego", "Peter"));
customerRepository.save(new Customer(3, "Peter", "John"));
customerRepository.save(new Customer(4, "Jason", "Bob"));
customerRepository.save(new Customer(5, "Merry", "kill"));
return "Save Operation Executed Successfully. Please call findall API.";
}
@RequestMapping("/findall")
public String findAll() {
String result = "";
Map<Long, Customer> customers = customerRepository.findAll();
for (Customer customer : customers.values()) {
result += customer.toString() + "<br>";
}
return result;
}
@RequestMapping("/find")
public String findById(@RequestParam("id") Long id) {
String result = "";
result = customerRepository.find(id).toString();
return result;
}
@RequestMapping(value = "/uppercase")
public String postCustomer(@RequestParam("id") Long id) {
Customer customer = customerRepository.find(id);
customer.setFirstName(customer.getFirstName().toUpperCase());
customer.setLastName(customer.getLastName().toUpperCase());
customerRepository.update(customer);
return "Uppercase Operation Executed Successfully. Please call findall API.";
}
@RequestMapping("/delete")
public String deleteById(@RequestParam("id") Long id) {
customerRepository.delete(id);
return "Delete Operation Executed Successfully. Please call findall API.";
}
}
package com.the.basic.tech.info.redis.model;
import java.io.Serializable;
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String firstName;
private String lastName;
protected Customer() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Customer(long id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
}
}
CustomerRepository interface declaration
package com.the.basic.tech.info.redis.repo;
import java.util.Map;
import com.the.basic.tech.info.redis.model.Customer;
public interface CustomerRepository {
void save(Customer customer);
Customer find(Long id);
Map<Long, Customer> findAll();
void update(Customer customer);
void delete(Long id);
}
CustomerRepositoryImpl Java Class with HashOperations as below
package com.the.basic.tech.info.redis.repo;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import com.the.basic.tech.info.redis.model.Customer;
@Repository
public class CustomerRepositoryImpl implements CustomerRepository {
private static final String KEY = "Customer";
private RedisTemplate<String, Object> redisTemplate;
private HashOperations<String, Long, Customer> hashOperations;
@Autowired
public CustomerRepositoryImpl(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@PostConstruct
private void init() {
hashOperations = redisTemplate.opsForHash();
}
@Override
public void save(Customer customer) {
hashOperations.put(KEY, customer.getId(), customer);
}
@Override
public Customer find(Long id) {
return hashOperations.get(KEY, id);
}
@Override
public Map<Long, Customer> findAll() {
return hashOperations.entries(KEY);
}
@Override
public void update(Customer customer) {
hashOperations.put(KEY, customer.getId(), customer);
}
@Override
public void delete(Long id) {
hashOperations.delete(KEY, id);
}
}
Run spring-boot-data-redis: mvn spring-boot:run
D:\development\spring-boot-data-redis>mvn spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-boot-data-redis 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.5.2:run (default-cli) > test-compile @ spring-boot-data-redis >>>
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-boot-data-redis ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-boot-data-redis ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-boot-data-redis ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] skip non existing resourceDirectory D:\development\spring-boot-data-redis\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-boot-data-redis ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.5.2:run (default-cli) < test-compile @ spring-boot-data-redis <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.5.2:run (default-cli) @ spring-boot-data-redis ---
[INFO] Attaching agents: []
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2021-06-29 21:40:00.034 INFO 24120 --- [ main] c.t.b.t.i.r.SpringDataRedisApplication : Starting SpringDataRedisApplication using Java 1.8.0_212 on LOCALHOST with PID 24120 (D:\development\spring-boot-data-redis\target\classes started by 172025 in D:\development\spring-boot-data-redis)
2021-06-29 21:40:00.049 INFO 24120 --- [ main] c.t.b.t.i.r.SpringDataRedisApplication : No active profile set, falling back to default profiles: default
2021-06-29 21:40:01.145 INFO 24120 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2021-06-29 21:40:01.149 INFO 24120 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2021-06-29 21:40:01.206 INFO 24120 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 28 ms. Found 0 Redis repository interfaces.
2021-06-29 21:40:02.776 INFO 24120 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-06-29 21:40:02.789 INFO 24120 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-06-29 21:40:02.791 INFO 24120 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.48]
2021-06-29 21:40:02.896 INFO 24120 --- [ main] o.a.c.c.C.[.[.[/springbootdataredis] : Initializing Spring embedded WebApplicationContext
2021-06-29 21:40:02.897 INFO 24120 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2737 ms
2021-06-29 21:40:03.506 INFO 24120 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '/springbootdataredis'
2021-06-29 21:40:03.525 INFO 24120 --- [ main] c.t.b.t.i.r.SpringDataRedisApplication : Started SpringDataRedisApplication in 4.45 seconds (JVM running for 5.485)
2021-06-29 21:40:07.281 INFO 24120 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/springbootdataredis] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-06-29 21:40:07.282 INFO 24120 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-06-29 21:40:07.289 INFO 24120 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
Now, Fetch Employees Data from Redis – Rest API (http://localhost:8080/springbootdataredis/findall)
Note: You can see updated record in Uppercase for id=3 as below
Record will be removed/deleted from Redis Cache.
Now, Fetch Employees Data from Redis – Rest API (http://localhost:8080/springbootdataredis/findall)
Keep learning. Have a great Day 🙂