Como o Spring Data funciona com Redis

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.




All Articles