Leçons du module (2/4)
Conditions de concurrence
Comprendre comment une base de données fonctionne de manière isolée sur un seul terminal est simple, mais dans un scénario Web réel, il y aura des centaines de processus « Node/PHP/Go » simultanés envoyant des requêtes. C’est là que naissent les fameuses Race Conditions.
Le problème "Mise à jour perdue"
La mise à jour perdue se produit lorsque deux threads lisent la même ancienne ligne, font des calculs dessus sur le serveur JavaScript, puis renvoient la MISE À JOUR pour enregistrer le résultat.
Scénario:
- Le produit #5 contient 10 unités.
- L'utilisateur A en achète un (le serveur A lit "10", calcule "9").
- Dans la même milliseconde, l'utilisateur B en achète un autre avant que l'achat de A ne termine la phase COMMIT.
- Le serveur B lit également "10", calcule "9".
- Le serveur A envoie
UPDATE: set quantity = 9. - Le serveur B envoie
UPDATE: set quantity = 9. - Tous deux pensent avoir réussi à diminuer le nombre. Mais la valeur finale aurait dû être de 8 unités ! Un achat fantôme a été perdu.
Solution sans transactions lourdes (Atomic Updates)
Au lieu de lire et de faire les calculs à l'extérieur, laissez la base de données le faire pendant la mise à jour elle-même, qui est toujours synchronisée.
-- Wrong
UPDATE products SET stock = 9 WHERE id = 5;
-- Correct and natively thread-safe
UPDATE products SET stock = stock - 1 WHERE id = 5;Anomalies plus extrêmes (Dirty Reads & Phantoms)
- Dirty Read : Vous lisez les données temporaires de quelqu'un d'autre qui n'ont pas encore été confirmées par un COMMIT (et pourriez soudainement passer à ROLLBACK vous invalidant).
- Lectures fantômes : Vous effectuez une analyse de toutes les lignes, pendant ce temps un deuxième thread insère un nouvel enregistrement, puis vous effectuez une autre analyse au cours de la même transaction et vous trouvez comme par magie que le nouvel enregistrement est apparu de nulle part, compromettant les rapports financiers calculés.
Modifiez atomiquement l'enregistrement du client pour une petite manipulation de chaîne. Disons que nous voulons renommer la « ville » d'un client pour ajouter un astérisque. Faites-le en exploitant la propre valeur de la ligne pour celle avec l'identifiant = 10, en concaténant ' - Old' à la valeur actuelle (utilisez le tube de concaténation || de postgres).
Afficher l'indice
MISE À JOUR des clients SET city = city || ' - Ancien' OÙ id = 10 ;
Solution disponible après 3 tentatives
Une mise à jour classique perdue se produit dans les paiements et les prix. Disons qu'il y a une hausse de prix d'urgence : augmentez le 'unit_price' de la table 'order_items' (pour le produit 1 de la commande 1) de 20 % de manière atomique, c'est-à-dire en le multipliant par * 1,2 au lieu d'insérer le nouveau prix précalculé manuellement dans JS.
Afficher l'indice
UPDATE order_items SET unit_price = unit_price * 1.2 O order_id = 1 ET product_id = 1 ;
Solution disponible après 3 tentatives