Redis is an open source(BSD licensed) in-memory remote data structure store(database) that offers high performance, replication, and a unique data model. The full form of Redis is Remote Directory Server. Moreover, we can use it in multiple forms. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams.
You can use Redis from most programming languages. Redis is written in ANSI C and works in most POSIX systems like Linux, *BSD, and OS X, without external dependencies. Linux and OS X are the two operating systems where Redis is developed and tested the most.
Redis is a NoSQL DB of type Key-Value stores. In fact, Redis Database is an in-memory database that persists on disk. It means when we use Redis Database, we occupy a memory on the disk to use as a Database. The data model is key-value, but many several kind of values are supported such as Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps etc.
๐๐ผ๐ ๐ฑ๐ผ๐ฒ๐ ๐ฅ๐ฒ๐ฑ๐ถ๐ ๐ฑ๐ฎ๐๐ฎ๐ฏ๐ฎ๐๐ฒ ๐๐ผ๐ฟ๐ธ ?
Unlike other databases such as MongoDB, PostgreSQL, Oracle, Cassandra that store data on disk or SSDs, all Redis data resides in-memory. As it doesnโt need to access disks, it avoids seek time delays. As a result, it can access data in microseconds. Each Redis database instance has a key space linked with it which is nothing but a wrapper on hash table implementation. Whatever data Redis stores such as string, redis set or redis hash, everything is saved inside the hash tables.
๐ช๐ต๐ฎ๐ ๐ฎ๐ฟ๐ฒ ๐๐ต๐ฒ ๐ฏ๐ฒ๐ป๐ฒ๐ณ๐ถ๐๐ ๐ผ๐ณ ๐ฅ๐ฒ๐ฑ๐ถ๐ ?
i) In-memory data store
ii) Flexible data structures : like Strings, Lists, Sets, Sorted Sets, Hashes, Bitmaps, HyperLoglogs
iii) Simplicity and ease-of-use
iv) High availability and scalability
v) Easy for Replication and persistence
vi) High Extensibility
๐ฆ๐ฝ๐ฟ๐ถ๐ป๐ด ๐๐ผ๐ผ๐ ๐ฅ๐ฒ๐ฑ๐ถ๐ ๐๐ฅ๐จ๐ ๐๐ ๐ฎ๐บ๐ฝ๐น๐ฒ
Letโs consider an Employee entity to develop our example.
๐ฆ๐๐ฒ๐ฝ#๐ญ: ๐๐ฟ๐ฒ๐ฎ๐๐ฒ ๐ฎ ๐ป๐ฒ๐ ๐ฆ๐ฝ๐ฟ๐ถ๐ป๐ด ๐๐ผ๐ผ๐ ๐ฆ๐๐ฎ๐ฟ๐๐ฒ๐ฟ ๐ฃ๐ฟ๐ผ๐ท๐ฒ๐ฐ๐ ๐๐๐ถ๐ป๐ด ๐ฆ๐ง๐ฆ
Letโs create a Spring Boot Starter project using STS. While creating Starter Project select โSpring Data Redisโ, โLombokโ, and โSprong Boot DevToolsโ as starter project dependencies. Please note that like โSpring Data JPAโ in relational databases, we will use โSpring Data Redisโ here in case of redis database.
๐ฆ๐๐ฒ๐ฝ#๐ฎ: ๐จ๐ฝ๐ฑ๐ฎ๐๐ฒ ๐ฎ๐ฝ๐ฝ๐น๐ถ๐ฐ๐ฎ๐๐ถ๐ผ๐ป.๐ฝ๐ฟ๐ผ๐ฝ๐ฒ๐ฟ๐๐ถ๐ฒ๐
For this example, updating the application.properties is optional. This is because the value of below properties are internally configured by Redis by default.
spring.redis.host=localhost
spring.redis.port=6379
๐ฆ๐๐ฒ๐ฝ#๐ฏ: ๐๐ฟ๐ฒ๐ฎ๐๐ฒ ๐ฎ ๐๐ผ๐ป๐ณ๐ถ๐ด ๐ฐ๐น๐ฎ๐๐ ๐ฎ๐ ๐๐ฝ๐ฝ๐๐ผ๐ป๐ณ๐ถ๐ด.๐ท๐ฎ๐๐ฎ
This class will work as a configuration class, just to create a DB connection between our application and Redis DB.
//configuration class
@Configuration
public class AppConfig {
//Creating Connection with Redis
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory();
}
//Creating RedisTemplate for Entity 'Employee'
@Bean
public RedisTemplate<String, Employee> redisTemplate(){
RedisTemplate<String, Employee> empTemplate = new RedisTemplate<>();
empTemplate.setConnectionFactory(redisConnectionFactory());
return empTemplate;
}
}
๐ฆ๐๐ฒ๐ฝ#๐ฐ: ๐๐ฟ๐ฒ๐ฎ๐๐ฒ ๐ฎ ๐บ๐ผ๐ฑ๐ฒ๐น ๐ฐ๐น๐ฎ๐๐ ๐ฎ๐ ๐๐บ๐ฝ๐น๐ผ๐๐ฒ๐ฒ.๐ท๐ฎ๐๐ฎ
Now create a model class Entity.java as below. For the simplicity, we have taken three fields of different data types here. Moreover, we donโt need to apply @Entity annotation to tell DB that this is an Entity because there is even no concept of Entity. But while using Redis concept, make sure that our model class should implement java.io.Serializable interface.
//Employee Class
@Data
@NoArgsConstructor
@AllArgsConstructor
//No @Entity concept here
public class Employee implements Serializable {
private static final long serialVersionUID = -7817224776021728682L;
private Integer empId;
private String empName;
private Double empSalary;
}
๐ฆ๐๐ฒ๐ฝ#๐ฑ: ๐๐ฟ๐ฒ๐ฎ๐๐ฒ ๐ฎ๐ป ๐๐ป๐๐ฒ๐ฟ๐ณ๐ฎ๐ฐ๐ฒ ๐ฎ๐ ๐๐๐ข ๐น๐ฎ๐๐ฒ๐ฟ
Letโs create an interface at DAO layer and declare the methods of CRUD operations. We will name it as IEmployeeDao.java.
//Employee interface DAO
public interface IEmployeeDao {
void saveEmployee(Employee emp);
Employee getOneEmployee(Integer id);
void updateEmployee(Employee emp);
Map<Integer, Employee> getAllEmployees();
void deleteEmployee(Integer id);
void saveAllEmployees(Map<Integer, Employee> map);
}
๐ฆ๐๐ฒ๐ฝ#๐ฒ: ๐๐ฟ๐ฒ๐ฎ๐๐ฒ ๐ฎ๐ป ๐ถ๐บ๐ฝ๐น๐ฒ๐บ๐ฒ๐ป๐๐ฎ๐๐ถ๐ผ๐ป ๐ฐ๐น๐ฎ๐๐ ๐ณ๐ผ๐ฟ ๐๐ป๐๐ฒ๐ฟ๐ณ๐ฎ๐ฐ๐ฒ ๐ฎ๐ ๐๐๐ข ๐น๐ฎ๐๐ฒ๐ฟ
Letโs create EmployeeDaoImpl.java class and implement the methods from the interface IEmployeeDao.java as below. This is the class of our primary interest as it will have implementation of all methods. Here, we need to declare a variable of type HashOperations as a HAS-A relation. It will help us to implement CRUD methods and reduce the coding efforts.
//Employee impl
@Repository
public class EmployeeDaoImpl implements IEmployeeDao {
private final String hashReference= "Employee";
@Resource(name="redisTemplate") // 'redisTemplate' is defined as a Bean in AppConfig.java
private HashOperations<String, Integer, Employee> hashOperations;
@Override
public void saveEmployee(Employee emp) {
//creates one record in Redis DB if record with that Id is not present
hashOperations.putIfAbsent(hashReference, emp.getEmpId(), emp);
}
@Override
public void saveAllEmployees(Map<Integer, Employee> map) {
hashOperations.putAll(hashReference, map);
}
@Override
public Employee getOneEmployee(Integer id) {
return hashOperations.get(hashReference, id);
}
@Override
public void updateEmployee(Employee emp) {
hashOperations.put(hashReference, emp.getEmpId(), emp);
}
@Override
public Map<Integer, Employee> getAllEmployees() {
return hashOperations.entries(hashReference);
}
@Override
public void deleteEmployee(Integer id) {
hashOperations.delete(hashReference, id);
}
}
๐๐ผ๐ ๐๐ผ ๐๐ฒ๐๐ ๐๐ต๐ฒ ๐ถ๐บ๐ฝ๐น๐ฒ๐บ๐ฒ๐ป๐๐ฒ๐ฑ ๐บ๐ฒ๐๐ต๐ผ๐ฑ๐ ?
In order to test the functionality of methods, we will create a Runner class that will implement CommandLineRunner.
๐ฆ๐๐ฒ๐ฝ#๐ญ : ๐๐ฟ๐ฒ๐ฎ๐๐ฒ ๐ฎ ๐ฅ๐๐ป๐ป๐ฒ๐ฟ ๐ฐ๐น๐ฎ๐๐ ๐๐ผ ๐๐ฒ๐๐ ๐ฎ๐น๐น ๐๐ต๐ฒ ๐บ๐ฒ๐๐ต๐ผ๐ฑ๐
Now create a Runner class and test all methods that we defined in EmployeeDaoImpl.java class.
//Command line runner for redis operations
@Component
public class RedisOpertionsRunner implements CommandLineRunner {
@Autowired
private IEmployeeDao empDao;
@Override
public void run(String... args) throws Exception {
//saving one employee
empDao.saveEmployee(new Employee(500, "Emp0", 2150.0));
//saving multiple employees
empDao.saveAllEmployees(
Map.of( 501, new Employee(501, "Emp1", 2396.0),
502, new Employee(502, "Emp2", 2499.5),
503, new Employee(503, "Emp4", 2324.75)
)
);
//modifying employee with empId 503
empDao.updateEmployee(new Employee(503, "Emp3", 2325.25));
//deleting employee with empID 500
empDao.deleteEmployee(500);
//retrieving all employees
empDao.getAllEmployees().forEach((k,v)-> System.out.println(k +" : "+v));
//retrieving employee with empID 501
System.out.println("Emp details for 501 : "+empDao.getOneEmployee(501));
}
}
In order to test the implemented method, we need to start the Redis Server.
๐ฆ๐๐ฒ๐ฝ#๐ฏ : ๐ฅ๐๐ป ๐ฆ๐ฝ๐ฟ๐ถ๐ป๐ด ๐๐ผ๐ผ๐ ๐ฃ๐ฟ๐ผ๐ท๐ฒ๐ฐ๐
Right Click on the project, select Run As -> Spring Boot Project.
Finally you can get output including all operations. However, we can test individual methods separately by commenting other methods.