Verrous de lignes : FOR UPDATE, SKIP LOCKED
AvancéQuand plusieurs transactions décident à partir de la même ligne, on la verrouille pour sérialiser l'accès et éviter les mises à jour perdues.
BEGIN;
SELECT stock FROM produits WHERE id = 42 FOR UPDATE; -- verrou exclusif sur la ligne
UPDATE produits SET stock = stock - 1 WHERE id = 42;
COMMIT;
Mieux : laisser la base faire l'opération atomiquement#
-- Une seule instruction atomique : pas de verrou explicite nécessaire
UPDATE produits
SET stock = stock - 1
WHERE id = 42 AND stock > 0
RETURNING stock; -- 0 ligne renvoyée = rupture de stock
Les modes de verrouillage#
| Clause | Usage |
|---|---|
FOR UPDATE | Je vais modifier ou supprimer cette ligne |
FOR NO KEY UPDATE | Je modifie sans toucher aux clés (moins bloquant pour les clés étrangères) |
FOR SHARE | Je lis et je veux empêcher toute modification |
NOWAIT | Échoue immédiatement plutôt que d'attendre le verrou |
SKIP LOCKED | Ignore les lignes déjà verrouillées par d'autres |
File de tâches avec SKIP LOCKED#
-- Chaque worker prend une tâche non encore traitée, sans bloquer les autres
UPDATE taches
SET statut = 'en_cours', demarre_le = now()
WHERE id = (
SELECT id FROM taches
WHERE statut = 'a_faire'
ORDER BY cree_le
LIMIT 1
FOR UPDATE SKIP LOCKED
)
RETURNING *;
Cas pratique :
FOR UPDATE SKIP LOCKEDtransforme une table PostgreSQL en file de tâches fiable pour des volumes modérés (jusqu'à quelques milliers de tâches par seconde) : pas de double traitement, pas d'attente entre workers, et l'atomicité de la base.