Maison >Java >javaDidacticiel >Méthodes de requête de flux Spring Data JPA

Méthodes de requête de flux Spring Data JPA

Patricia Arquette
Patricia Arquetteoriginal
2024-11-22 05:35:20820parcourir

Spring Data JPA Stream Query Methods

Introduction

Traditionnellement, la récupération de grandes quantités de données peut solliciter les ressources mémoire, car cela implique souvent de charger l'intégralité de l'ensemble de résultats en mémoire.

=> Les méthodes de requête de flux offrent une solution en fournissant un moyen de traiter les données de manière incrémentale à l'aide de Java 8 Streams. Cela garantit que seule une partie des données est conservée en mémoire à tout moment, améliorant les performances et l'évolutivité.

Dans cet article de blog, nous approfondirons le fonctionnement des méthodes de requête de flux dans Spring Data JPA, explorerons leurs cas d'utilisation et démontrerons leur implémentation.

Pour ce guide, nous utilisons :

  • IDE : IntelliJ IDEA (recommandé pour les applications Spring) ou Eclipse
  • Version Java : 17
  • Version Spring Data JPA : 2.7.x ou supérieure (compatible avec Spring Boot 3.x)
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

REMARQUE : pour des exemples plus détaillés, veuillez visiter mon référentiel GitHub ici

1. Que sont les méthodes de requête de flux ?

Les méthodes de requête Stream dans Spring Data JPA nous permettent de renvoyer les résultats de la requête sous forme de flux au lieu d'une liste ou d'autres types de collection. Cette approche offre plusieurs avantages :

  • Gestion efficace des ressources : les données sont traitées de manière incrémentielle, réduisant ainsi la surcharge de mémoire.

  • Traitement paresseux : les résultats sont récupérés et traités à la demande, ce qui est idéal pour des scénarios tels que la pagination ou le traitement par lots.

  • Intégration avec la programmation fonctionnelle : les flux s'adaptent aux fonctionnalités de programmation fonctionnelle de Java, permettant des opérations telles que le filtrage, la cartographie et la collecte.

2. Comment utiliser les méthodes de requête de flux ?

=> Imaginons que nous développons une application e-commerce et que nous souhaitons :

  • Récupérez tous les clients qui ont passé des commandes après une date précise.
  • Filtrer les commandes dont le montant total est supérieur à un montant spécifique fourni.
  • Regroupez les clients en fonction de la valeur totale de leurs commandes au cours des 6 derniers mois.
  • Renvoyer les données sous forme de résumé des noms des clients et de la valeur totale de leurs commandes.

Entités

  • Client : représente un client.
@Setter
@Getter
@Entity
@Entity(name = "tbl_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String email;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Order> orders;
}
  • Commande : représente une commande passée par un client.
@Setter
@Getter
@Entity(name = "tbl_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Double amount;
    private LocalDateTime orderDate;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

Référentiel

  • CustomerRepository utilisé pour sélectionner les clients et leurs commandes associées passées après une date spécifique. Et nous avons utilisé Stream au lieu de Liste pour gérer le résultat de la requête.
public interface CustomerRepository extends JpaRepository<Customer, Long> {
    @Query("""
                SELECT c FROM tbl_customer c JOIN FETCH c.orders o WHERE o.orderDate >= :startDate
            """)
    @QueryHints(
            @QueryHint(name = AvailableHints.HINT_FETCH_SIZE, value = "25")
    )
    Stream<Customer> findCustomerWithOrders(@Param("startDate") LocalDateTime startDate);
}

REMARQUE :

  • Le JOIN FETCH garantit que les commandes sont chargées avec impatience.

  • Les @QueryHints utilisés pour fournir des astuces supplémentaires au JPA (par exemple, Hibernate) pour optimiser l'exécution de la requête.

=> Par exemple, lorsque ma requête renvoie 100 enregistrements :

  • Les 25 premiers enregistrements sont récupérés et traités par l'application.
  • Une fois ceux-ci traités, les 25 suivants sont récupérés, et ainsi de suite, jusqu'à ce que les 100 enregistrements soient traités.
  • Ce comportement minimise l'utilisation de la mémoire et évite de charger les 100 enregistrements en mémoire en même temps.

Service

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Voici la classe de service pour traiter les données avec deux paramètres startDate et minOrderAmount. Comme vous pouvez le voir, nous ne filtrons pas en utilisant une requête SQL et chargeons toutes les données sous forme de flux, puis filtrons et regroupons par notre code Java.

Contrôleur

@Setter
@Getter
@Entity
@Entity(name = "tbl_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String email;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Order> orders;
}

Tests

=> Pour créer des données à tester, vous pouvez exécuter le script suivant dans mon code source ou l'ajouter vous-même.

src/main/resources/dummy-data.sql

Demande :

  • Date de début : 2024-05-01T00:00:00
  • Montant minimum de la commande : 100
@Setter
@Getter
@Entity(name = "tbl_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Double amount;
    private LocalDateTime orderDate;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

Réponse :

  • Renvoyer tous les clients avec leur montant total égal ou supérieur à minOrderAmount.
public interface CustomerRepository extends JpaRepository<Customer, Long> {
    @Query("""
                SELECT c FROM tbl_customer c JOIN FETCH c.orders o WHERE o.orderDate >= :startDate
            """)
    @QueryHints(
            @QueryHint(name = AvailableHints.HINT_FETCH_SIZE, value = "25")
    )
    Stream<Customer> findCustomerWithOrders(@Param("startDate") LocalDateTime startDate);
}

3. Flux vs Liste

=> Vous pouvez utiliser IntelliJ Profiler pour surveiller l'utilisation de la mémoire et le temps d'exécution. Pour plus de détails sur la façon d'ajouter et de tester avec un grand ensemble de données, vous pouvez le trouver dans mon référentiel GitHub

Petit ensemble de données : (10 clients, 100 commandes)

  • Stream : temps d'exécution (~ 5 ms), utilisation de la mémoire (faible)
  • Liste : Temps d'exécution (~4 ms), Utilisation de la mémoire (faible)

Grand ensemble de données (10 000 clients, 100 000 commandes)

  • Stream : temps d'exécution (~ 202 ms), utilisation de la mémoire (modérée)
  • Liste : Temps d'exécution (~ 176 ms), Utilisation de la mémoire (élevée)

Mesures de performances

Metric Stream List
Initial Fetch Time Slightly slower (due to lazy loading) Faster (all at once)
Memory Consumption Low (incremental processing) High (entire dataset in memory)
Memory Consumption Low (incremental processing) High (entire dataset in memory)
Processing Overhead Efficient for large datasets May cause memory issues for large datasets
Batch Fetching Supported (with fetch size) Not applicable
Error Recovery Graceful with early termination Limited, as data is preloaded

Conclusion

Les méthodes de requête de flux Spring Data JPA offrent un moyen élégant de traiter efficacement de grands ensembles de données tout en exploitant la puissance des flux Java. En traitant les données de manière incrémentielle, ils réduisent la consommation de mémoire et s'intègrent parfaitement aux paradigmes de programmation fonctionnelle modernes.

Que pensez-vous des méthodes de requête de flux ? Partagez vos expériences et cas d'utilisation dans les commentaires ci-dessous !

On se retrouve dans les prochains posts. Bon codage !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn