sql >> Database >  >> RDS >> PostgreSQL

Atomic UPDATE .. SELECT in Postgres

Hoewel de suggestie van Erwin mogelijk de eenvoudigste is manier om correct gedrag te krijgen (zolang u uw transactie opnieuw probeert als u een uitzondering krijgt met SQLSTATE van 40001) werken wachtrijapplicaties van nature beter met verzoeken die worden geblokkeerd voor een kans om hun beurt in de wachtrij te krijgen dan met de PostgreSQL-implementatie van SERIALIZABLE transacties, wat een hogere gelijktijdigheid mogelijk maakt en iets "optimistischer" is over de kans op botsingen.

De voorbeeldquery in de vraag, zoals deze er nu uitziet, in de standaard READ COMMITTED transactie-isolatieniveau zou twee (of meer) gelijktijdige verbindingen mogelijk maken om beide dezelfde rij uit de wachtrij te "claimen". Wat er zal gebeuren is dit:

  • T1 start en komt zo ver als het vergrendelen van de rij in de UPDATE fase.
  • T2 overlapt T1 in uitvoeringstijd en probeert die rij bij te werken. Het blokkeert in afwachting van de COMMIT of ROLLBACK van T1.
  • T1 commit, nadat hij de rij met succes heeft "geclaimd".
  • T2 probeert de rij bij te werken, vindt die T1 al heeft, zoekt naar de nieuwe versie van de rij, vindt dat deze nog steeds voldoet aan de selectiecriteria (wat precies dat id is overeenkomsten) en "claimt" ook de rij.

Het kan worden aangepast om correct te werken (als u een versie van PostgreSQL gebruikt die de FOR UPDATE toestaat clausule in een subquery). Voeg gewoon FOR UPDATE . toe aan het einde van de subquery die de id selecteert, en dit zal gebeuren:

  • T1 start en vergrendelt nu de rij voordat selecteert de id.
  • T2 overlapt T1 in uitvoeringstijd en blokken tijdens het selecteren van een id, in afwachting van de COMMIT of ROLLBACK van T1.
  • T1 commit, nadat hij de rij met succes heeft "geclaimd".
  • Tegen de tijd dat T2 kan lezen de rij om de id te zien, ziet hij dat deze is geclaimd, dus vindt hij de volgende beschikbare id.

Bij de REPEATABLE READ of SERIALIZABLE transactie-isolatieniveau, zou het schrijfconflict een fout veroorzaken, die u zou kunnen opvangen en vaststellen dat het een serialisatiefout was op basis van de SQLSTATE, en het opnieuw proberen.

Als u over het algemeen SERIALISEERBARE transacties wilt, maar nieuwe pogingen in het wachtrijgebied wilt vermijden, kunt u dat mogelijk bereiken door een adviserende vergrendeling te gebruiken.



  1. Postgresql wijzig kolomtype van int in UUID

  2. OTA instellen in R12 en 11i

  3. Vind index van het laatste voorkomen van een subtekenreeks met behulp van T-SQL

  4. Kan pg gem niet installeren op Windows