Uw opties zijn:
-
Uitvoeren in
SERIALIZABLEisolatie. Onderling afhankelijke transacties worden afgebroken bij commit omdat ze een serialisatiefout hebben. U krijgt veel spam in het foutenlogboek en u zult het vaak opnieuw proberen, maar het zal betrouwbaar werken. -
Definieer een
UNIQUEbeperking en probeer het opnieuw bij een mislukking, zoals u opmerkte. Dezelfde problemen als hierboven. -
Als er een bovenliggend object is, kunt u
SELECT ... FOR UPDATEhet bovenliggende object voordat u uwmax. doet vraag. In dit geval zou uSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE. Je gebruiktbarals slot voor allefoos met diebar_id. U kunt dan weten dat het veilig is om door te gaan, zolang elke query die uw teller doet dit op betrouwbare wijze doet. Dit kan best goed werken.Dit voert nog steeds een geaggregeerde query uit voor elke oproep, wat (per volgende optie) niet nodig is, maar het spamt in ieder geval het foutenlogboek niet zoals de bovenstaande opties.
-
Gebruik een aanrechttafel. Dit is wat ik zou doen. Ofwel in
bar, of in een bijzettafel zoalsbar_foo_counter, verkrijg een rij-ID metUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counterof de minder efficiënte optie als uw framework
RETURNINGniet aankan :SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;Dan, in dezelfde transactie , gebruik de gegenereerde tellerrij voor het
number. Wanneer je commit, de tellertabelrij voor diebar_idwordt ontgrendeld voor de volgende te gebruiken query. Als je terugdraait, wordt de wijziging genegeerd.
Ik raad de baliebenadering aan, met behulp van een speciale zijtafel voor de teller in plaats van een kolom toe te voegen aan bar . Dat is schoner om te modelleren en betekent dat u minder update-bloat in bar creëert , wat zoekopdrachten kan vertragen tot bar .