</>
Plan du cours — 35/64

Upsert et idempotence : ON CONFLICT

Avancé

L'INSERT ... ON CONFLICT rend l'écriture atomique et rejouable : « insère, ou met à jour si elle existe déjà », sans course entre un SELECT et un INSERT.

INSERT INTO compteurs (cle, valeur)
VALUES ('visites', 1)
ON CONFLICT (cle)
DO UPDATE SET valeur = compteurs.valeur + EXCLUDED.valeur;   -- EXCLUDED = la ligne proposée

INSERT INTO utilisateurs (email, nom)
VALUES ('alice@exemple.fr', 'Alice')
ON CONFLICT (email) DO NOTHING
RETURNING id;                       -- rien renvoyé si la ligne existait déjà

Clés d'idempotence#

Pour qu'un client puisse réessayer un paiement ou une création sans doublon, on enregistre une clé unique fournie par l'appelant :

CREATE TABLE paiements (
    id               bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    cle_idempotence  text NOT NULL UNIQUE,
    montant          numeric(12, 2) NOT NULL
);

INSERT INTO paiements (cle_idempotence, montant)
VALUES ($1, $2)
ON CONFLICT (cle_idempotence) DO NOTHING
RETURNING id;

Si aucune ligne n'est renvoyée, la requête a déjà été traitée : renvoyez le résultat précédent.

Piège : SELECT puis INSERT si absent n'est pas atomique : deux requêtes concurrentes peuvent toutes deux ne rien trouver et insérer un doublon. Laissez la contrainte UNIQUE et ON CONFLICT arbitrer.