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

Lås og transaktion i postgres, der skulle blokere en forespørgsel

Den adfærd, du beskriver, er normal og forventet i enhver transaktionel relationel database.

Hvis PostgreSQL viste dig værdien edited for den første SELECT det ville være forkert at gøre det - det kaldes "dirty read" og er dårlige nyheder i databaser.

PostgreSQL ville have lov til at vente ved SELECT indtil du har forpligtet dig eller rullet tilbage, men det er ikke påkrævet af SQL-standarden, du har ikke fortalt den, at du vil vente, og den behøver ikke vente af nogen teknisk årsag, så den returnerer de data, du har bedt om for straks. Når alt kommer til alt, indtil den er begået, den update kun en slags eksisterer - det kan stadig ske eller måske ikke ske.

Hvis PostgreSQL altid ventede her, ville du hurtigt havne i en situation, hvor kun én forbindelse kunne gøre noget med databasen ad gangen. Ikke kønt for ydeevnen, og totalt unødvendigt det meste af tiden.

Hvis du vil vente på en samtidig UPDATE (eller DELETE ), skal du bruge SELECT ... FOR SHARE . (Men vær opmærksom på, at dette ikke virker for INSERT ).

Detaljer:

SELECT uden en FOR UPDATE eller FOR SHARE klausul tager ikke nogen rækkeniveaulåse. Så den ser, hvad der er den aktuelle forpligtede række, og er ikke påvirket af nogen transaktioner under flyvningen, der muligvis ændrer denne række. Begreberne er forklaret i MVCC-afsnittet i dokumenterne . Den generelle idé er, at PostgreSQL er copy-on-write, med versionering, der gør det muligt at returnere den korrekte kopi baseret på, hvad transaktionen eller erklæringen kunne "se" på det tidspunkt, den startede - hvad PostgreSQL kalder et "snapshot".

I standarden READ COMMITTED isolationssnapshots tages på sætningsniveauet, så hvis du SELECT en række, COMMIT en ændring til den fra en anden transaktion, og SELECT igen, vil du se forskellige værdier, selv inden for en enkelt transaktion. Du kan bruge SNAPSHOT isolation, hvis du ikke ønsker at se ændringer foretaget efter transaktionens begyndelse, eller SERIALIZABLE isolation for at tilføje yderligere beskyttelse mod visse former for indbyrdes afhængighed af transaktioner.

Se transaktionsisoleringskapitlet i dokumentationen .

Hvis du ønsker en SELECT for at vente på igangværende transaktioner for at begå eller rollback ændringer til rækker, der vælges, skal du bruge SELECT ... FOR SHARE . Dette vil blokere på låsen taget af en UPDATE eller DELETE indtil transaktionen, der tog låsen, ruller tilbage eller forpligter.

INSERT er dog anderledes - tuplerne eksisterer bare ikke for andre transaktioner, før de er forpligtet. Den eneste måde at vente på samtidig INSERT s er at tage en EXCLUSIVE Lås på bordniveau, så du ved, at ingen andre ændrer tabellen, mens du læser den. Normalt betyder behovet for at gøre det, at du har et designproblem i applikationen - din app burde ikke pleje hvis der er ucommitterede insert er stadig på flugt.

Se dokumentationens eksplicitte låsningskapitel .



  1. Kan ikke implementere til Heroku, fordi serveren nægtede forbindelsen

  2. hvordan man undgår at få forkert ID

  3. Hvordan får man ledige datoer med reservationer?

  4. ÆNDRE TABEL uden at låse bordet?