Redis (servidor de dicionário remoto) é merecidamente considerado um homem velho no mundo das soluções NoSql. Esta postagem é sobre como Spring Data trabalha com isso. A ideia de escrever este post surgiu porque o Redis não é exatamente como um banco de dados familiar, ele suporta tipos de dados que não são convenientes de usar para armazenar objetos (o cache não conta) e para pesquisar determinados campos. Aqui, com exemplos, tentarei descrever como o Spring Data trabalha com ele por meio dos familiares CrudRepository e QueryDSL. Este não é um exemplo de HowTo, do qual existem muitos. Quem se interessa pelo interior vai mais longe.
Os exemplos serão baseados em um projeto simples . O Redis surge em um contêiner docker, um aplicativo de inicialização rápida que também se comunica com ele no contêiner. O aplicativo contém um modelo simples, repositório, serviço e controlador. Você pode tocar em tudo isso através do swagger em localhost: 8080.
Além dos comandos que o serviço executa no banco de dados, também fornecerei um pequeno pseudocódigo que descreve mais claramente o que está acontecendo.
Vamos trabalhar com a entidade Aluno:
@Data
@AllArgsConstructor
@NoArgsConstructor
@RedisHash("Student")
public class Student {
@Id
private String id;
private String name;
private int age;
}Aqui, é necessário esclarecer que a anotação @RedisHash("Student")diz sob qual chave todas as entidades serão agregadas.
Vamos tentar manter o primeiro aluno:
curl -X POST "http://localhost:8080/save" -H "accept: */*" -H "Content-Type: application/json" -d "{\"id\":\"1\",\"name\":\"Stephen\",\"age\":12}"3 comandos foram executados:
"DEL" "Student:1"
"HMSET" "Student:1" "_class" "com.odis.redisserviceweb.model.Student" "id" "1" "name" "Stephen" "age" "12"
"SADD" "Student" "1" , - "DEL" "Student:1", "Student:1". @RedisHash + @Id.
"HMSET" "Student:1" "_class" "com.odis.redisserviceweb.model.Student" "id" "1" "name" "Stephen" "age" "12". "Student:1". -
Map "Student:1";
"Student:1".put("_class", "com.odis.redisserviceweb.model.Student");
"Student:1".put("id", "1");
"Student:1".put("name", "Stephen");
"Student:1".put("age", "12"); - "SADD" "Student" "1" - "Student" "1".
? Redis. - "Student:1", - "Student".
keys * - ( ) :
127.0.0.1:6379> keys *
1) "Student"
2) "Student:1", :
127.0.0.1:6379> type "Student"
set
127.0.0.1:6379> type "Student:1"
hash- ? .
@Id :
curl -X GET "http://localhost:8080/get/1" -H "accept: */*""Student:1" , :
"HGETALL" "Student:1"
1) "_class"
2) "com.odis.redisserviceweb.model.Student"
3) "id"
4) "1"
5) "name"
6) "Stephen"
7) "age"
8) "12", , :
curl -X POST "http://localhost:8080/save" -H "accept: */*" -H "Content-Type: application/json" -d "{\"id\":\"2\",\"name\":\"Macaulay\",\"age\":40}"
curl -X GET "http://localhost:8080/get" -H "accept: */*"3 :
"SMEMBERS" "Student"
1) "1"
2) "2"
"HGETALL" "Student:1"
1) "_class"
2) "com.odis.redisserviceweb.model.Student"
3) "id"
4) "1"
5) "name"
6) "Stephen"
7) "age"
8) "12"
127.0.0.1
"HGETALL" "Student:2"
1) "_class"
2) "com.odis.redisserviceweb.model.Student"
3) "id"
4) "2"
5) "name"
6) "Macaulay"
7) "age"
8) "40" . - "Student" - , "Student:@Id". , O (N) N - .
:
curl -X DELETE "http://localhost:8080/delete/1" -H "accept: */*":
"HGETALL" "Student:1"
1) "_class"
2) "com.odis.redisserviceweb.model.Student"
3) "id"
4) "1"
5) "name"
6) "Stephen"
7) "age"
8) "12"
"DEL" "Student:1"
(integer) 1
"SREM" "Student" "1"
(integer) 1
"SMEMBERS" "Student:1:idx"
(empty array)
"DEL" "Student:1:idx"
(integer) 0, Id . "Student" "1".
Student:1:idx. . , . :
List<Student> findAllByName(String name);:
curl -X POST "http://localhost:8080/save" -H "accept: */*" -H "Content-Type: application/json" -d "{\"id\":\"1\",\"name\":\"Stephen\",\"age\":12}"
curl -X GET "http://localhost:8080/get/filter/Stephen" -H "accept: */*", Redis :
"SINTER" "Student:name:Stephen"
(empty array) "SINTER" - , , - "Student:name:Stephen" .
, , @Id, @Indexed Spring Data , . . Redis . name :
@Data
@AllArgsConstructor
@NoArgsConstructor
@RedisHash("Student")
public class Student {
@Id
private String id;
@Indexed
private String name;
private int age;
}:
curl -X POST "http://localhost:8080/save" -H "accept: */*" -H "Content-Type: application/json" -d "{\"id\":\"1\",\"name\":\"Stephen\",\"age\":12}":
"DEL" "Student:1"
"HMSET" "Student:1" "_class" "com.odis.redisserviceweb.model.Student" "id" "1" "name" "Stephen" "age" "12"
"SADD" "Student" "1"
"SADD" "Student:name:Stephen" "1"
"SADD" "Student:1:idx" "Student:name:Stephen" , : "Student:name:Stephen" , , @Indexed . Id . Id Stephen Id . , . - :
Map "Student:1";
"Student:1".put("_class", "com.odis.redisserviceweb.model.Student");
"Student:1".put("id", "1");
"Student:1".put("name", "Stephen");
"Student:1".put("age", "12");
Set "Student";
"Student".add("1");
Set "Student:name:Stephen";
"Student:name:Stephen".add("1");
Set "Student:1:idx";
"Student:1:idx".add("Student:name:Stephen");, , Redis :
"SINTER" "Student:name:Stephen"
"HGETALL" "Student:1" Id , . .
SINTER . id .
.
, Spring Data Redis. Spring.
A desvantagem é que os campos nos quais a pesquisa será realizada devem ser marcados @Indexedcom uma anotação desde o início. Caso contrário, "índices" só serão criados para recursos que são retidos após a adição desta anotação. E sim, entendo que o Redis não é a melhor solução para tais necessidades, mas se, devido a uma determinada situação, for necessário utilizá-lo, SpringData o poderá fazer muito bem.