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 :
- lire la donnée avec sa version actuelle (
version = 3) - modifier la donnée en mémoire
- au moment du
UPDATE, vérifier que la version n'a pas changé - 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à chaqueUPDATE - lance
OptimisticLockExceptionsi 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
@Versionavec JPA est le moyen le plus simple en Java- préférer un numéro de version à un timestamp
- gérer
OptimisticLockExceptionavec un retry ou un message utilisateur