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 .