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 :
<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
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.
=> Imaginons que nous développons une application e-commerce et que nous souhaitons :
Entités
@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; }
@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
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 :
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 :
@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 :
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); }
=> 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)
Grand ensemble de données (10 000 clients, 100 000 commandes)
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 |
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!