Aller au contenu

Optimistic Locking

Contexte

Quand plusieurs transactions accèdent simultanément à la même donnée, il y a un risque de lost update — une transaction écrase les modifications d'une autre.

L'optimistic locking résout ce problème sans verrouiller les lignes en base.


Principe

L'optimistic locking repose sur un numéro de version :

  1. lire la donnée avec sa version actuelle (version = 3)
  2. modifier la donnée en mémoire
  3. au moment du UPDATE, vérifier que la version n'a pas changé
  4. si la version a changé → conflit détecté, transaction rejetée
UPDATE orders
SET status = 'CONFIRMED', version = 4
WHERE id = 42 AND version = 3;

Si version a été modifiée entre-temps, le WHERE ne matche rien → 0 rows updated → conflit.


Optimistic vs Pessimistic Locking

Aspect Optimistic Pessimistic
Verrouillage Au moment de l'écriture Au moment de la lecture
SQL WHERE version = ? SELECT ... FOR UPDATE
Conflits Détectés à l'écriture Empêchés par le lock
Performance Meilleure (pas de lock en base) Dégradée sous charge
Cas d'usage Conflits rares Conflits fréquents

Implémentation JPA / Hibernate

@Entity
public class Order {

    @Id
    @GeneratedValue
    private Long id;

    private String status;

    @Version
    private Integer version;
}

Hibernate gère automatiquement :

  • incrémente version à chaque UPDATE
  • lance OptimisticLockException si la version ne correspond pas

Gestion de l'exception

try {
    orderRepository.save(order);
} catch (OptimisticLockException e) {
    // Recharger la donnée et réessayer, ou informer l'utilisateur
    Order fresh = orderRepository.findById(order.getId()).orElseThrow();
    // appliquer la modification sur la version fraîche
}

Avec un timestamp

Alternative à la version numérique :

@Version
private Instant lastModified;

Moins fiable — deux modifications dans la même milliseconde ne sont pas détectées. La version numérique est préférable.


Quand l'utiliser

  • applications web classiques (les conflits sont rares)
  • systèmes à forte charge (évite les locks en base)
  • APIs REST avec PUT/PATCH (inclure la version dans le body ou un header If-Match)

Quand l'éviter

  • scénarios avec conflits fréquents (compteur partagé, stock limité)
  • transactions longues où le risque de conflit augmente

À retenir

  • optimistic locking détecte les conflits au lieu de les empêcher
  • @Version avec JPA est le moyen le plus simple en Java
  • préférer un numéro de version à un timestamp
  • gérer OptimisticLockException avec un retry ou un message utilisateur

Voir aussi