sql >> Database teknologi >  >> RDS >> PostgreSQL

Atomic OPDATERING .. VÆLG i Postgres

Mens Erwins forslag muligvis er det simpelste måde at få korrekt adfærd på (så længe du prøver din transaktion igen, hvis du får en undtagelse med SQLSTATE af 40001), har kø-applikationer i sagens natur en tendens til at fungere bedre med anmodninger, der blokerer for en chance for at tage deres tur i køen end med PostgreSQL-implementeringen af ​​SERIALIZABLE transaktioner, hvilket tillader højere samtidighed og er noget mere "optimistisk" med hensyn til chancerne for kollision.

Eksempelforespørgslen i spørgsmålet, som det står, i standard READ COMMITTED transaktionsisoleringsniveau ville tillade to (eller flere) samtidige forbindelser til begge at "kræve" den samme række fra køen. Hvad der vil ske er dette:

  • T1 starter og når så langt som til at låse rækken i UPDATE fase.
  • T2 overlapper T1 i udførelsestid og forsøger at opdatere denne række. Den blokerer afventende COMMIT eller ROLLBACK af T1.
  • T1 forpligter sig efter at have "gjort krav på" rækken.
  • T2 forsøger at opdatere rækken, finder ud af, at T1 allerede har, leder efter den nye version af rækken, finder ud af, at den stadig opfylder udvælgelseskriterierne (som bare er det id matcher), og "gør krav på" rækken.

Det kan ændres til at fungere korrekt (hvis du bruger en version af PostgreSQL, som tillader FOR UPDATE klausul i en underforespørgsel). Bare tilføj FOR UPDATE til slutningen af ​​underforespørgslen, som vælger id'et, og dette vil ske:

  • T1 starter og låser nu rækken, før du vælger id.
  • T2 overlapper T1 i udførelsestid og blokerer, mens du prøver at vælge et id, afventer COMMIT eller ROLLBACK af T1.
  • T1 forpligter sig efter at have "gjort krav på" rækken.
  • På det tidspunkt, T2 er i stand til at læse rækken for at se id'et, ser den, at den er blevet gjort krav på, så den finder det næste tilgængelige id.

Ved REPEATABLE READ eller SERIALIZABLE transaktionsisolationsniveau, ville skrivekonflikten give en fejl, som du kunne fange og fastslå var en serialiseringsfejl baseret på SQLSTATE, og prøve igen.

Hvis du generelt ønsker SERIALISERBARE transaktioner, men du vil undgå genforsøg i køområdet, kan du muligvis opnå det ved at bruge en rådgivende lås.



  1. Undgå at navngive brugerlagrede procedurer SP% eller SP_%

  2. Flere indekser vs Multi-kolonne indekser

  3. Liquibase lås - årsager?

  4. Sådan genereres INSERT-sætninger fra en forespørgsel, når du bruger SQLcl (Oracle)