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;
}