Redis peut-il être utilisé comme base de données relationnelle ?

        Découvrez à quel point il est facile d'utiliser Redis avec Java + Spring et découvrez cinq différences par rapport aux bases de données relationnelles.

        Commençons par la question « Comment utilisez-vous Redis ? » Je suis sûr que la plupart des gens l'utilisent comme cache pour les services. J'espère que vous savez qu'il peut faire plus que cela. Récemment, j'ai fait un rapport lors d'une conférence sur la façon dont nous avons déplacé certaines données vers Redis et comment la demande a été acheminée pour la première fois vers Redis. Maintenant, ce que je veux vous dire, ce n'est pas comment nous l'appliquons, mais le fait que lorsque vous utilisez Spring et ses abstractions, vous ne remarquerez peut-être pas immédiatement cette substitution.
        Essayons d'écrire une petite application Spring qui utilisera deux bases de données PostgreSQL et Redis. Je voudrais souligner que ce que nous allons stocker dans la base de données n'est pas une sorte d'objet plat, mais un objet à part entière provenant d'une base de données relationnelle avec des champs imbriqués (jointures internes). Pour ce faire, nous devons installer des plugins dans Redis, tels que RedisJSON et RediSearch. Le premier nous permet de stocker des objets au format JSON, et le second nous permet de rechercher par n'importe quel champ de l'objet, même les champs imbriqués.
        Pour utiliser une base de données relationnelle, nous choisirons Spring Data JPA. Pour utiliser Redis, nous utiliserons l'excellente bibliothèque Redis OM Spring, qui vous permet de travailler avec des bases de données à un niveau abstrait. Il s'agit d'un analogue de Data JPA. Sous le capot, Redis OM Spring possède toutes les dépendances nécessaires pour que Spring et Jedis fonctionnent avec la base de données. Nous n’entrerons pas dans les détails car cet article n’en parle pas.

écrivons le code

Alors écrivons du code. Supposons que nous devions écrire une "downtime"entité qui appelle la base de données. Dans cette entité, j'ai ajouté d'autres objets tels que "place", "reason"et d'autres objets.

Entités d'une base de données relationnelle :

@Entity
@Table(schema = "test", name = "downtime")
public class Downtime {

    @Id
    private String id;
    private LocalDateTime beginDate;
    private LocalDateTime endDate;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "area")
    private Place area;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "cause")
    private Cause cause;
    ...

Ce code n'a pas besoin de commentaires. Nous devons faire la même chose pour Redis.

 Objet Redis :

@Document
public class DowntimeDoc {

    @Id
    @Indexed
    private String id;
    @Indexed
    private LocalDateTime beginDate;
    private LocalDateTime endDate;
    @Indexed
    private PlaceDoc area;
    @Indexed
    private CauseDoc cause;
    ....

Dans cet exemple, @Entitynous utilisons plutôt @Document. Cette annotation indique que notre objet est une entité. Il sera stocké dans la base de données avec la clé "chemin du package + nom de la classe + Idx".

Cette @Indexedannotation signifie qu'elle sera indexée pour la recherche. Si cette annotation n'est pas spécifiée, le champ sera enregistré dans la base de données, mais la recherche du champ renverra des résultats vides. Vous pouvez ajouter cette annotation si vous le souhaitez. Les données déjà présentes dans la base de données seront indexées de manière asynchrone ; les nouvelles données seront indexées de manière synchrone. 

Ensuite, nous allons créer un référentiel dont le rôle principal est de récupérer les données de la base de données.

Exemples de bases de données relationnelles :

public interface DowntimeRepository extends JpaRepository<Downtime, String> {
}

Exemple Redis :

public interface DowntimeRedisRepository extends RedisDocumentRepository<DowntimeDoc, String> {
}

La différence est que nous étendons l'interface actuelle RedisDocumentRepository, qui étend l'interface CRUD standard de Spring.

Ajoutons une méthode pour trouver le premier temps d'arrêt dû à la raison que nous avons spécifiée.

public interface DowntimeRepository extends JpaRepository<Downtime, String> {

    Downtime findFirstByCauseIdOrderByBeginDate(String causeId);
}

La même chose est vraie pour Redis :

public interface DowntimeRedisRepository extends RedisDocumentRepository<DowntimeDoc, String> {

    DowntimeDoc findTopByCause_IdOrderByBeginDateAsc(String causeId);
}

Comme vous l'avez remarqué, si vous écrivez du code qui utilise la base de données via des abstractions , la différence est à peine perceptible. De plus, Redis OM Spring vous permet d' @Queryécrire vous-même des requêtes à l'aide d'annotations, tout comme dans Spring Data JPA.

Voici un exemple de requête HQL :

@Query("SELECT d FROM Downtime d" +
        " JOIN FETCH d.area " +
        " JOIN FETCH d.cause" +
        " JOIN FETCH d.fixer" +
        " JOIN FETCH d.area.level " +
        " WHERE d.area IN ?1 AND (d.beginDate BETWEEN ?2 AND ?3 OR d.cause IN ?4) ")
List<Downtime> findAllByParams(List<Place> workPlace, LocalDateTime start, LocalDateTime end, List<Cause> causes);

Il en va de même pour Redis :

@Query("(@area_id:{$areas} ) & (@beginDate:[$start $end] | @cause_id:{$causes})")
Page<DowntimeDoc> findByParams(@Param("areas") List<String> areas,
                               @Param("start") long start,
                               @Param("end") long end,
                               @Param("causes") List<String> causes, Pageable pageable);

Pour Redis, il suffit de préciser “WHERE”l'état de cette pièce. Il n'est pas nécessaire d'indiquer quels champs doivent être ajoutés, car ils sont toujours extraits de la base de données. Cependant, nous ne pouvons pas extraire tous les champs et utiliser “returnFields”des paramètres supplémentaires pour spécifier exactement ce dont nous avons besoin. Vous pouvez également spécifier l'ordre, les limites et les décalages - ces derniers, d'ailleurs, ne sont pas possibles dans HQL. Dans cet exemple, je passe Pageableà la méthode selon laquelle cela fonctionnera au niveau de la base de données au lieu d'extraire toutes les données dans le service et de les élaguer là-bas (comme c'est le cas avec Hibernate).

De plus, Redis OM Spring vous permet d'écrire des requêtes à l'aide de EntityStream, ce qui est similaire à l'API Stream.

Vous trouverez ci-dessous un exemple utilisant la requête ci-dessus EntityStream.


entityStream
        .of(DowntimeDoc.class)
        .filter(DowntimeDoc$.AREA_ID.in(filter.getWorkPlace().toArray(String[]::new)))
        .filter(between + " | " + causes)
        .map(mapper::toEntity)
        .collect(Collectors.toList());

Dans cet exemple, j'utilise un filtre qui utilise le métamodèle, en passant le paramètre sous forme de chaîne au deuxième filtre pour montrer que les deux options sont valides. Vous l'avez deviné : EntityStreamaccepte un ensemble d'opérations intermédiaires et exécute cet ensemble lorsqu'une opération de terminal est invoquée.

Nuances de printemps Redis OM

Laissez-moi vous expliquer quelques nuances de l'utilisation de Redis OM Spring :

  • Vous ne pourrez pas utiliser les UUID comme clés primaires. Vous pouvez le spécifier sous forme de chaîne et il sera indexé. Mais lors de la recherche, vous devez échapper aux espaces@id :
{2e5af82m\-02af\-553b\-7961\-168878aa521е}

Encore une chose : si vous RedisDocumentRepositoryeffectuez une recherche dans le référentiel, rien ne fonctionne car il y a une telle expression dans le code qui supprimera tous les écrans :

String regex = "(\\$" + key + ")(\\W+|\\*|\\+)(.*)";

Par conséquent, pour effectuer une recherche selon ces champs, vous devez écrire des requêtes directement dans RediSearch. J'ai un exemple de la façon de procéder dans un projet de démonstration.

  • Dans la RedisDocumentRepositoryméthode de recherche, si vous attendez une collection, vous devez passer un paramètre Pageableindiquant la taille de la ligne attendue ou @Querypréciser la taille dans ;. Sinon, vous recevrez jusqu'à 10 enregistrements.
  • Cette FT.SEARCH (@Query)méthode ne prend en charge qu'un seul paramètre pour le tri. Ceci est résolu en écrivant une requête FT.AGGREGATE (@Aggregation).

La liste ci-dessus n'est pas exhaustive. J'ai trouvé beaucoup de choses différentes lors de l'utilisation de ces bibliothèques, mais il s'agit simplement d'une spécificité d'implémentation de base de données. Enfin, je n'ai pas inclus d'informations sur le plugin Redis dans cet article, ni parlé de toutes les fonctionnalités de Redis OM Spring ; sinon l'article serait trop volumineux pour être lu.

en conclusion

J'ai montré qu'actuellement, Redis vous permet de stocker des objets avec de grands nids et vous permet de rechercher les champs de cet objet. Si vous travaillez avec des données via des abstractions dans des référentiels, certaines personnes pourraient ne voir aucune différence avec Spring Data JPA, surtout si vous utilisez des requêtes simples telles que , , , etc. et une requête par nom de Saveméthode .deletefindAllBy

Supongo que te gusta

Origin blog.csdn.net/qq_28245905/article/details/132311874
Recomendado
Clasificación