Implémentation de l'audit et du verrouillage optimiste avec Spring Data JPA

La traçabilité des entités dans les architectures de persistance modernes exige la conservation automatique des métadonnées relatives à la création et aux mutations. Spring Data JPA intègre un intercepteur natif qui permet de capturer ces informations sans surcharger la logique métier. Paralèlement, la gestion des accès concurrents s'appuie généralement sur une stratégie de verrouillage optimiste pour prévenir les collisions lors des mises à jour parallèles.

Configuration de la traçabilité

Le premier prérequis consiste à fournir au contexte de persistance l'identité de l'acteur courant. Cela se fait via une classe implémentant l'interface AuditorAware :

@Component
public class ContexteOperateur implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        // Extraction depuis le contexte d'authentification ou la session
        return Optional.ofNullable(IdentifiantSession.recupererActif());
    }
}

L'activation du module s'effectue directement sur la classe de configuration principale :

@EnableJpaAuditing

Sur les entités, l'écouteur AuditingEntityListener doit être enregistré. Chaque champ de métadonnée reçoit ensuite une annotation dédiée pour lier le cycle de vie JPA aux informations techniques :

@CreatedBy
private String operateurCreation;

@CreatedDate
private LocalDateTime instantCreation;

@LastModifiedBy
private String operateurDerniereModif;

@LastModifiedDate
private LocalDateTime instantDerniereModif;

Une limitation inhérente à ce mécanisme est l'absence de suivi pour les suppressions physiques, puisque l'enregistrement disparaît de la table. L'alternative courante consiste à implémenter une suppression douce via un indicateur booléen. Notez que le bon fonctionnement de cette fonctionnalité nécessite la dépendence spring-aspects dans le classpaht.

Stratégie de verrouillage optimiste

Pour sécuriser les écritures simultanées, le verrouillage optimiste applique un contrôle de version à chaque ligne. Un champ spécifique est incrémenté à chaque mutation réussie.

@Version
private Long numeroRevision;

Lors de l'exécution d'une opération de mise à jour, le fournisseur de persistance injecte automatiquement une condition de concordance dans la clause WHERE. Si la version en base diffère de celle chargée en mémoire, la requête échoue, signalant un conflit :

UPDATE reference_article SET libelle=?, montant=?, revision=? WHERE code=? AND revision=?

Abstraction commune pour les entités

Pour éviter la redondance de code à travers le modèle domaine, il est recommandé de factoriser ces propriétés dans une classe parente. L'annotation @MappedSuperclass signale que cette structure ne génère pas de table propre, mais que ses attributs seront propagés aux sous-classes mappées.

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class EntiteBase implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long clePrimaire;

    @CreatedBy
    protected String operateurCreation;

    @LastModifiedBy
    protected String operateurModif;

    @CreatedDate
    protected LocalDateTime dateCreation;

    @LastModifiedDate
    protected LocalDateTime dateModif;

    @Version
    private Long versionControle;
}

Étiquettes: spring-data-jpa jpa-auditing optimistic-locking java-persistence-api entity-mapping

Publié le 22 août à 11h52