sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL och ActiveRecord underval för tävlingstillstånd

Dina alternativ är:

  • Kör i SERIALIZABLE isolering. Interberoende transaktioner kommer att avbrytas vid commit eftersom de har ett serialiseringsfel. Du kommer att få massor av skräppost i felloggar och du kommer att göra många försök igen, men det kommer att fungera tillförlitligt.

  • Definiera en UNIQUE begränsning och försök igen vid misslyckande, som du noterade. Samma problem som ovan.

  • Om det finns ett överordnat objekt kan du SELECT ... FOR UPDATE det överordnade objektet innan du gör ditt max fråga. I det här fallet skulle du SELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE . Du använder bar som ett lås för alla foo s med det bar_id . Du kan då veta att det är säkert att fortsätta, så länge som varje fråga som gör din räknarökning gör detta på ett tillförlitligt sätt. Detta kan fungera ganska bra.

    Detta gör fortfarande en samlad fråga för varje samtal, vilket (per nästa alternativ) är onödigt, men det spammar åtminstone inte felloggen som ovanstående alternativ.

  • Använd ett bänkbord. Det här är vad jag skulle göra. Antingen i bar , eller i en sidotabell som bar_foo_counter skaffa ett rad-ID med

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

    eller det mindre effektiva alternativet om ditt ramverk inte kan hantera RETURNING :

    SELECT counter FROM bar_foo_counter
    WHERE bar_id = $1 FOR UPDATE;
    
    UPDATE bar_foo_counter SET counter = $1;
    

    Sedan i samma transaktion , använd den genererade räknarraden för number . När du commit, räknartabellraden för den bar_id låses upp för nästa fråga att använda. Om du rullar tillbaka kasseras ändringen.

Jag rekommenderar att räknaren använder en dedikerad sidotabell för räknaren istället för att lägga till en kolumn i bar . Det är renare att modellera och innebär att du skapar mindre uppdateringsuppsvällning i bar , vilket kan sakta ner frågor till bar .




  1. java.lang.UnsupportedOperationException:org.hibernate.dialect.Oracle10gDialect stöder inte resultatuppsättningar via lagrade procedurer

  2. Resten i PostgreSQL, MS SQL Server, MySQL och SQLite

  3. Oracle-sekvenser motsvarande i MySQL

  4. Hur man konverterar MySQL JSON-array till kommaseparerad sträng