Spring Data JPA @Modifying Annotation

1. Introduction

Dans ce court didacticiel, nous allons apprendre à créer des requêtes de mise à jour avec l' annotation Spring Data JPA @Query . Nous y parviendrons en utilisant l' annotation @Modifying .

Tout d'abord, nous allons rafraîchir notre mémoire et voir comment effectuer des requêtes à l'aide de Spring Data JPA. Après cela, nous allons approfondir l'utilisation des annotations @Query et @Modifying . Enfin, nous verrons comment gérer l'état de notre contexte de persistance lors de l'utilisation de requêtes de modification.

2. Interrogation dans Spring Data JPA

Tout d'abord, récapitulons les 3 mécanismes fournis par Spring Data JPA pour interroger des données dans une base de données :

  • Méthodes de requête
  • Annotation @Query
  • Implémentation de référentiel personnalisé

Créons une classe User et un référentiel Spring Data JPA correspondant pour illustrer ces mécanismes:

@Entity @Table(name = "users", schema = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private LocalDate creationDate; private LocalDate lastLoginDate; private boolean active; private String email; }
public interface UserRepository extends JpaRepository {}

Le mécanisme des méthodes de requête nous permet de manipuler les données en dérivant les requêtes à partir des noms de méthode:

List findAllByName(String name); void deleteAllByCreationDateAfter(LocalDate date);

Dans cet exemple, nous pouvons trouver une requête qui récupère les utilisateurs par leurs noms, ou encore une requête qui supprime les utilisateurs ayant une date de création après une certaine date.

Quant à l' annotation @Query , elle nous offre la possibilité d'écrire une requête JPQL ou SQL spécifique dans l' annotation @Query :

@Query("select u from User u where u.email like '%@gmail.com'") List findUsersWithGmailAddress();

Dans cet extrait de code, nous pouvons voir une requête récupérant les utilisateurs ayant une adresse e-mail @ gmail.com .

Le premier mécanisme nous permet de récupérer ou de supprimer des données. Quant au second, il nous permet d'exécuter à peu près n'importe quelle requête. Cependant, pour mettre à jour les requêtes, nous devons ajouter l' annotation @Modifying . Ce sera le sujet de ce tutoriel.

3. Utilisation de l' annotation @Modifying

L' annotation @Modifying est utilisée pour améliorer l' annotation @Query afin d'exécuter non seulement des requêtes SELECT, mais également des requêtes INSERT , UPDATE , DELETE et même DDL .

Jouons un peu avec cette annotation et voyons de quoi elle est faite.

Tout d'abord, voyons un exemple de requête @Modifying UPDATE:

@Modifying @Query("update User u set u.active = false where u.lastLoginDate < :date") void deactivateUsersNotLoggedInSince(@Param("date") LocalDate date);

Ici, nous désactivons les utilisateurs qui ne se sont pas connectés depuis une date donnée.

Essayons un autre où nous supprimerons les utilisateurs désactivés:

@Modifying @Query("delete User u where u.active = false") int deleteDeactivatedUsers();

Comme nous pouvons le voir, cette méthode renvoie un entier. C'est une fonctionnalité des requêtes Spring Data JPA @Modifying qui nous fournit le nombre d'entités mises à jour.

Nous devons noter que l'exécution d'une requête de suppression avec @Query fonctionne différemment des méthodes de requête dérivées du nom deleteBy de Spring Data JPA . Ce dernier récupère d'abord les entités de la base de données puis les supprime une par une. Ainsi, cela signifie que la méthode de cycle de vie @PreRemove sera appelée sur ces entités. Cependant, avec le premier, une seule requête est exécutée sur la base de données.

Enfin, ajoutons une colonne supprimée à notre table USERS avec une requête DDL :

@Modifying @Query(value = "alter table USERS.USERS add column deleted int(1) not null default 0", nativeQuery = true) void addDeletedColumn();

Malheureusement, l'utilisation de requêtes de modification laisse le contexte de persistance sous-jacent obsolète. Cependant, il est possible de gérer cette situation. C'est le sujet de la section suivante.

4. Gestion du contexte de persistance

Si notre requête de modification change les entités contenues dans le contexte de persistance, alors ce contexte devient obsolète. Une façon de gérer cette situation consiste à effacer le contexte de persistance. En faisant cela, nous nous assurons que le contexte de persistance récupérera les entités de la base de données la prochaine fois.

Cependant, nous n'avons pas besoin d'appeler explicitement la méthode clear () sur EntityManager . Nous pouvons simplement utiliser la propriété clearAutomatically de l' annotation @Modifying :

@Modifying(clearAutomatically = true)

De cette façon, nous nous assurons que le contexte de persistance est effacé après l'exécution de notre requête.

Mais que se passerait-il si notre contexte de persistance contenait des modifications non réglées? Par conséquent, l'effacer signifierait abandonner les modifications non enregistrées. Heureusement, il existe une autre propriété de l'annotation que nous pouvons utiliser - flushAutomatically :

@Modifying(flushAutomatically = true)

Maintenant, l' EntityManager est vidé avant que notre requête ne soit exécutée.

5. Conclusion

Cela conclut ce court article sur l' annotation @Modifying . Nous avons vu comment utiliser cette annotation pour exécuter des requêtes de mise à jour telles que INSERT, UPDATE, DELETE et même DDL . Après cela, nous avons appris à gérer l'état du contexte de persistance avec les propriétés clearAutomatically et flushAutomatically .

Comme d'habitude, le code complet de cet article est disponible à l'adresse over sur GitHub.