PostgreSQL kommer med solida, beprövade funktioner som låter dig definiera exakt vad som ska hända när flera klienter försöker uppdatera samma data samtidigt. En av dem är isoleringsnivån för transaktioner.
Läs vidare för att lära dig mer om hur transaktionsisolering fungerar i PostgreSQL.
Transaktioner och isoleringsnivå
Transaktioner är det grundläggande sättet att mutera data i ett RDBMS. Modern RDBMS tillåter mer än en transaktion att köras samtidigt, och kommer följaktligen med en mängd olika verktyg – vissa standard, vissa RDBMS-specifika – för programutvecklare att specificera hur deras transaktioner ska eller inte ska interagera med andra transaktioner.
Transaktionsisoleringsnivåer och pessimistiska lås är två sådana verktyg. Även om dessa är nödvändiga för dataintegritet och prestanda, är de tyvärr inte intuitiva att förstå eller använda.
Isoleringsnivån för en transaktion, i PostgreSQL, kan vara en av:
- Läs engagerad
- Repeterbar läsning
- Serialiserbar
Varje transaktion har sin isoleringsnivå inställd på en av dessa när den skapas. Standardnivån är "read committed".
Observera att SQL-standarden också definierar "läs oengagerad", vilket inte stöds i Postgres. Du måste använda närmaste, högre nivå av "läs engagerad".
Låt oss se vad dessa nivåer betyder.
Läs engagerad
Vad händer när en (oavslutad) transaktion infogar rader i en tabell och den andra (också oavslutade) transaktionen försöker läsa alla rader i tabellen? Om den här andra transaktionen kan se raderna som infogas av den första, kallas den läsningen en smutsig läsning – eftersom den första transaktionen kan återställas och den andra transaktionen skulle ha läst "fantomrader" som aldrig funnits.
Den lästa engagerade isoleringsnivån garanterar att smutsiga läsningar aldrig kommer att inträffa. Här är ett exempel:
Som du kan se kunde den andra transaktionen inte läsa den första transaktionens ännu ej fastställda data. I PostgreSQL är det inte möjligt att sänka isoleringsnivån till under denna nivå så att smutsiga läsningar tillåts.
Repeterbar läsning
Ännu ett problem är det med icke-repeterbara läsningar. Dessa händer när en transaktion läser en rad och sedan läser den igen lite senare men får ett annat resultat - eftersom raden uppdaterades däremellan av en annan transaktion. Läsningen har blivit ej repeterbar , som visas i det här exemplet:
För att åtgärda detta problem, ställ in isoleringsnivån för transaktionen till "repeatableread". PostgreSQL kommer sedan att se till att den andra (eller någon) läsning också returnerar samma resultat som den första läsningen. Här är samma scenario på den uppgraderade isoleringsnivån:
Observera att isoleringsnivån specificerades tillsammans med BEGIN-satsen. Det är också möjligt att specificera detta på anslutningsnivå (som en anslutningsparameter), som en konfigurationsparameter (default_transaction_isolation
)och använda SET TRANSACTION-satsen.
Serialiserbar
Nästa isoleringsnivå tar upp problemet med förlorade uppdateringar . Uppdateringar som utförs i en transaktion kan "förloras" eller skrivas över av en annan transaktion som råkar köras samtidigt, som visas här:
Här blockerar den andra transaktionens UPPDATERING, eftersom PostgreSQL låser sig för att förhindra ytterligare en uppdatering tills den första transaktionen är klar. Den första transaktionens ändring går dock förlorad, eftersom den andra "skriver över" raden.
Om den här typen av beteende inte är acceptabelt kan du uppgradera isoleringsnivån till serialiserbar:
På denna nivå misslyckas commit av den andra transaktionen. Den andra transaktionens handlingar baserades på fakta som gjordes ogiltiga när den skulle genomföras.
Även om serialisering ger den högsta säkerhetsnivån, betyder det också att applikationen måste upptäcka sådana commit-fel och försöka om hela transaktionen.