sql >> Databasteknik >  >> RDS >> PostgreSQL

Lås och transaktion i postgres som borde blockera en fråga

Beteendet du beskriver är normalt och förväntat i alla transaktionsrelationsdatabaser.

Om PostgreSQL visade dig värdet edited för den första SELECT det skulle vara fel att göra det - det kallas "smutsig läsning" och är dåliga nyheter i databaser.

PostgreSQL skulle få vänta vid SELECT tills du har begått eller rullat tillbaka, men det krävs inte enligt SQL-standarden, du har inte sagt till den att du vill vänta, och den behöver inte vänta av någon teknisk anledning, så den returnerar data du frågade om för omedelbart. När allt kommer omkring, tills den är genomförd, den update bara existerar - det kan fortfarande hända eller kanske inte hända.

Om PostgreSQL alltid väntade här, skulle du snabbt hamna i en situation där endast en anslutning kunde göra vad som helst med databasen åt gången. Inte snyggt för prestanda, och helt onödigt för det mesta.

Om du vill vänta på en samtidig UPDATE (eller DELETE ), skulle du använda SELECT ... FOR SHARE . (Men tänk på att detta inte fungerar för INSERT ).

Detaljer:

SELECT utan en FOR UPDATE eller FOR SHARE klausul tar inte några radnivålås. Så den ser vad som än är den aktuella raden, och påverkas inte av några transaktioner under flygning som kan ändra den raden. Begreppen förklaras i MVCC-delen av dokumenten . Den allmänna tanken är att PostgreSQL är copy-on-write, med versionshantering som gör att den kan returnera den korrekta kopian baserat på vad transaktionen eller uttalandet kunde "se" vid den tidpunkt då den startade - vad PostgreSQL kallar en "snapshot".

I standardinställningen READ COMMITTED isoleringsögonblicksbilder tas på satsnivå, så om du SELECT en rad, COMMIT en ändring av den från en annan transaktion, och SELECT igen kommer du att se olika värden även inom en överföring. Du kan använda SNAPSHOT isolering om du inte vill se ändringar som genomförs efter att transaktionen påbörjats, eller SERIALIZABLE isolering för att lägga till ytterligare skydd mot vissa typer av transaktioners beroenden.

Se kapitlet om transaktionsisolering i dokumentationen .

Om du vill ha en SELECT för att vänta på att pågående transaktioner ska utföra eller återställa ändringar av rader som väljs, måste du använda SELECT ... FOR SHARE . Detta kommer att blockera låset som tas av en UPDATE eller DELETE tills transaktionen som tog låset rullar tillbaka eller begår.

INSERT är dock annorlunda - tuplarna existerar helt enkelt inte för andra transaktioner förrän commit. Det enda sättet att vänta på samtidig INSERT s är att ta en EXCLUSIVE Lås på bordsnivå, så att du vet att ingen annan ändrar tabellen medan du läser den. Vanligtvis innebär behovet att göra det att du har ett designproblem i applikationen - din app borde inte bry sig om det finns oengagerade insert flyger fortfarande.

Se kapitlet om explicit låsning i dokumentationen .



  1. mysql-fel:FEL 1018 (HY000):Kan inte läsa dir av '.' (fel:13)

  2. PostgreSQL User Group NL

  3. Mysql + där klausul matchar flera rader

  4. sql-fråga för att extrahera unika poster