sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL en ActiveRecord subselecteren voor raceconditie

Uw opties zijn:

  • Uitvoeren in SERIALIZABLE isolatie. 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 UNIQUE beperking en probeer het opnieuw bij een mislukking, zoals u opmerkte. Dezelfde problemen als hierboven.

  • Als er een bovenliggend object is, kunt u SELECT ... FOR UPDATE het bovenliggende object voordat u uw max . doet vraag. In dit geval zou u SELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE . Je gebruikt bar als slot voor alle foo s met die bar_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 zoals bar_foo_counter , verkrijg een rij-ID met

    UPDATE bar_foo_counter SET counter = counter + 1
    WHERE bar_id = $1 RETURNING counter
    

    of de minder efficiënte optie als uw framework RETURNING niet 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 die bar_id wordt 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 .




  1. docker-compose up &&docker-compose build:fout met PostgreSQL

  2. cx_Oracle 'ORA-01843:geen geldige maand' met unicode-parameter

  3. Waarschuwing:mysql_fetch_object():opgegeven argument is geen geldige MySQL-resultaatbron

  4. Verschillende waarden selecteren uit twee tabellen