Vos options sont :
-
Exécuter en
SERIALIZABLE
isolation. Les transactions interdépendantes seront abandonnées lors de la validation en raison d'un échec de sérialisation. Vous recevrez beaucoup de spam dans le journal des erreurs et vous ferez de nombreuses tentatives, mais cela fonctionnera de manière fiable. -
Définir un
UNIQUE
contrainte et réessayer en cas d'échec, comme vous l'avez noté. Mêmes problèmes que ci-dessus. -
S'il existe un objet parent, vous pouvez
SELECT ... FOR UPDATE
l'objet parent avant de faire votremax
requête. Dans ce cas, vous devezSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE
. Vous utilisezbar
comme un verrou pour tous lesfoo
s avec cebar_id
. Vous pouvez alors savoir que vous pouvez continuer en toute sécurité, tant que chaque requête qui effectue l'incrémentation de votre compteur le fait de manière fiable. Cela peut très bien fonctionner.Cela fait toujours une requête agrégée pour chaque appel, ce qui (selon l'option suivante) n'est pas nécessaire, mais au moins cela ne spamme pas le journal des erreurs comme les options ci-dessus.
-
Utilisez une table de comptoir. C'est ce que je ferais. Soit en
bar
, ou dans une table d'appoint commebar_foo_counter
, obtenez un ID de ligne à l'aide deUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counter
ou l'option la moins efficace si votre framework ne peut pas gérer
RETURNING
:SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;
Ensuite, dans la même transaction , utilisez la ligne de compteur générée pour le
number
. Lorsque vous validez, la ligne de la table de compteur pour cebar_id
est déverrouillé pour la prochaine requête à utiliser. Si vous annulez, la modification est annulée.
Je recommande l'approche du compteur, en utilisant une table latérale dédiée pour le compteur au lieu d'ajouter une colonne à bar
. C'est plus propre à modéliser, et cela signifie que vous créez moins de ballonnement de mise à jour dans bar
, ce qui peut ralentir les requêtes à bar
.