Vaše možnosti jsou:
-
Spustit v
SERIALIZABLE
izolace. Vzájemně závislé transakce budou při potvrzení přerušeny jako mající selhání serializace. Budete dostávat spoustu spamu s protokoly chyb a budete to dělat spoustu opakování, ale bude to fungovat spolehlivě. -
Definujte
UNIQUE
omezení a opakujte pokus o selhání, jak jste poznamenali. Stejné problémy jako výše. -
Pokud existuje nadřazený objekt, můžete
SELECT ... FOR UPDATE
rodičovský objekt před provedenímmax
dotaz. V tomto případě bysteSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE
. Používátebar
jako zámek pro všechnyfoo
s tímtobar_id
. Pak můžete vědět, že je bezpečné pokračovat, pokud to spolehlivě provede každý dotaz, který provádí přírůstek vašeho počítadla. To může fungovat docela dobře.To stále provádí souhrnný dotaz pro každé volání, což (pro další možnost) je zbytečné, ale alespoň to nezasílá protokol chyb jako výše uvedené možnosti.
-
Použijte pultový stůl. Tohle bych udělal já. Buď v
bar
nebo v postranní tabulce jakobar_foo_counter
, získejte ID řádku pomocíUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counter
nebo méně efektivní možnost, pokud váš framework nezvládá
RETURNING
:SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;
Poté ve stejné transakci , použijte vygenerovaný řádek počítadla pro
number
. Když odevzdáte, řádek tabulky počítadla pro danýbar_id
se odemkne pro další dotaz k použití. Pokud se vrátíte zpět, změna se zahodí.
Doporučuji přístup počítadla, který místo přidávání sloupce do bar
používá vyhrazenou postranní tabulku pro počítadlo . To je modelování čistší a znamená to, že v bar
vytvoříte méně aktualizačního nadýmání , což může zpomalit dotazy na bar
.