Kapittel 8 · 8B · Forelesning 15

Samtidighet og låser

Notater kap. 16–17. Hvordan databasen faktisk gjennomtvinger isolation (I-en i ACID — at samtidige transaksjoner ikke skal forstyrre hverandre) når flere transaksjoner går samtidig — uten å bli for treg.

01 · Hvorfor

Klassiske anomalier

Før vi snakker om låser, må vi se hva som går galt uten dem. Disse fem mønstrene er årsaken til at samtidighetskontroll (concurrency control) finnes.

Lost update

T1 og T2 leser samme verdi X, oppdaterer den lokalt, og skriver tilbake. Den siste skrivingen «vinner» — den førstes oppdatering går tapt. Klassisk «to brukere tar ut penger samtidig»-feil.

Dirty read

T2 leser en verdi T1 har skrevet, men ikke committed. Hvis T1 aborter, har T2 jobbet på en fantasi-verdi.

Dirty write

T2 skriver over en verdi T1 har skrevet uten å ha lest den. Når begge transaksjoner skriver flere objekter, kan resultatet bli inkonsistent — som om delene kommer fra forskjellige transaksjoner.

Unrepeatable read (read skew)

T1 leser X to ganger. Mellom de to leseoperasjonene har T2 oppdatert X og committed. T1 ser to ulike verdier i samme transaksjon.

Incorrect summary

T1 beregner en aggregat (sum, count, avg) over et datasett mens T2 oppdaterer noen av elementene. Resultatet er hverken før- eller etter-bildet — det er en blanding.

Phantom read

T1 utfører en spørring to ganger. Mellom dem har T2 satt inn en ny rad som matcher predikatet. Den «dukker opp» i andre kjøring. Krever spesielle låser (forklart i seksjon 06 — range-/predikatlåser) for å unngå.

Eksempel — Lost update

Konto X = 100. T1 vil legge til 50, T2 vil legge til 30. Begge leser X først, regner ut, og skriver tilbake:

T1: r1(X=100) ............... w1(X=150) ; c1
T2: ......... r2(X=100) ; w2(X=130) ; c2 ............

Sluttverdi: X = 150 (T1 sin skriving overskriver T2 sin) — eller 130 om rekkefølgen er motsatt. Riktig svar var 180. Begge oppdateringer leste samme «gamle» X = 100, og én av dem ble effektivt slettet. Det skjer fordi ingen lås beskytter read-modify-write-sekvensen.

Eksempel — Dirty write

To transaksjoner registrerer samme salg, men fletter operasjonene slik at buyer og invoice ender opp ulike — Bob får varen, Alice får regningen:

Steg
T1
T2
1
w1(buyer = Alice)
·
2
·
w2(buyer = Bob)
3
·
w2(invoice = Bob)
4
w1(invoice = Alice)
·
5
c1, c2
·
buyer
invoice
Trykk «Neste» for å starte.
Steg 0 / 5
Sjekk · Anomalier
En transaksjon T1 utfører SELECT COUNT(*) FROM ordrer WHERE status='ny' to ganger. Mellom de to kjøringene har T2 satt inn en ny ordre med status='ny'. Hvilken anomali er dette?
ADirty read
BDirty write
CUnrepeatable read
DPhantom read
Phantom. Phantoms oppstår når et nytt rad-sett dukker opp på grunn av en INSERT (eller forsvinner pga. DELETE) som matcher T1 sitt predikat. Unrepeatable read handler om at en eksisterende rad endrer verdi mellom to SELECT-er. Forskjellen er hva slags låsing som trengs: phantoms krever predikat-/range-låser (låser som dekker «alle rader som matcher en WHERE» — vi kommer tilbake til dette), ikke bare radlåser.
Sjekk · Anomalier 2
T1 starter, leser X = 100. T2 oppdaterer X til 150 og committer. T1 leser X igjen og får 150. Hvilken anomali er dette?
ADirty read — T1 leste en uncommitted verdi
BLost update — T1 sin oppdatering forsvant
CUnrepeatable read — samme rad gir to ulike verdier i samme transaksjon
DPhantom read — en ny rad dukket opp
Unrepeatable read. T1 leser samme eksisterende rad to ganger og får ulik verdi fordi T2 oppdaterte committed mellom. Det er ikke dirty read — T2 hadde committed før T1 leste på nytt. Det er heller ikke phantom — phantoms handler om nye rader som matcher et predikat (INSERT/DELETE), ikke endrede verdier av eksisterende rader. Lost update krever at T1 selv skriver basert på den utdaterte lesningen.
02 · Låser

Shared og exclusive

Den enkleste mekanismen mot anomaliene: tving transaksjonene til å ta låser (markører som reserverer et dataelement for transaksjonen) før de leser/skriver, og slipp dem etterpå.

  • Shared (S, read lock) — flere transaksjoner kan holde S-lås på samme element samtidig.
  • Exclusive (X, write lock) — bare én transaksjon kan holde X-lås, og ingen andre kan ha S-lås samtidig.

Forholdet mellom dem oppsummeres i kompatibilitetsmatrisen:

Holder lås på X Vil sette lås
SX
EksisterendeS
X

Tommelfingerregel: writers lockes ut alle. Readers tolererer hverandre.

Låser administreres av en låstabell i RAM. Hver aktiv transaksjon har en oppføring som peker til de låsene den allerede holder («has locks») og de den venter på («wants locks»). Operasjoner som må vente blir blokkert (settes på vent til lås kan tildeles).

Sjekk · Låskompatibilitet
T1 holder en S-lås på X. T2 ber om en lås på X. Hvilke kombinasjoner går?
AT2 får S-lås umiddelbart; T2 må vente om den ber om X-lås
BT2 får både S og X umiddelbart
CT2 må vente uansett hva den ber om
DT2 får X-lås, T1 sin S oppgraderes til X
Riktig. S-låser er kompatible med andre S-låser (delt), men X-låser er eksklusive — én X-lås stenger ute alle andre. Tommelfingerregel: writers stenger ute alle, readers tolererer hverandre.
03 · 2PL

Two-phase locking

Bare det å bruke S/X-låser er ikke nok. Det er hvordan vi tar og slipper låsene som gir korrekthet:

2PL-regelen: Alle låser tas i en vokse-fase; så snart første lås er sluppet, går transaksjonen over til en krympe-fase hvor den bare kan slippe.

Resultatet ligner et fjell — låstellet vokser, peaker, og krymper. Aldri «tilbake opp» etter første unlock.

Tid → Antall låser lock point (toppen) Vokse-fase (bare ta låser) Krympe-fase (bare slipp)
2PL: antall holdte låser øker monotont (stadig) til lock point (det punktet hvor transaksjonen holder flest låser samtidig), deretter avtar monotont. Aldri vri.

Hovedteorem: Hvis alle transaksjoner følger 2PL, er enhver schedule de produserer conflict-serializable. Det er grunnen til at 2PL er den de-facto standarden.

Hvorfor virker det?

Tenk: hvis en kant Ti→Tj finnes i presedensgrafen (Ti hadde en konfliktende op før Tj), må Ti ha sluppet sin lås før Tj tok sin. Hvis det også var en kant Tj→Ti, måtte Ti ha sluppet, deretter tatt en ny lås — brudd på 2PL. Altså: 2PL ⇒ ingen sykler ⇒ conflict-serializable.

Sjekk · 2PL
En transaksjon T1 tar S-lås på A, leser A, slipper S-låsen, og prøver så å ta X-lås på B. Følger T1 2PL?
AJa, så lenge alle låser slippes til slutt
BNei — T1 slapp en lås før den tok en ny, brudd på vokse/krympe-regelen
CJa, fordi det var ulike dataelementer
DNei — S-låser kan ikke slippes før commit
Brudd på 2PL. Vokse/krympe-regelen sier: så snart en lås er sluppet, kan ingen ny lås tas. Det betyr ikke noe at det er ulike data eller ulike låstyper. (Strict 2PL er enda strengere: X-låser må holdes til commit/abort.)
Sjekk · 2PL-teoremet
Hva er det 2PL-hovedteoremet egentlig garanterer?
ASchedulen blir seriell (transaksjonene kjører én og én)
BSchedulen er conflict-serializable
CSchedulen er strict og dermed cascadeless
DIngen deadlocks kan oppstå
Conflict-serializability. 2PL gir presedensgrafer uten sykler — derfor er resultatet ekvivalent med en eller annen seriell ordning. Men operasjonene kan fortsatt være interleavet (ikke (A) seriell). Kun strict 2PL gir strict-egenskapen (C) — basic 2PL gjør ikke det. Og 2PL kan absolutt ende i deadlock (D) — det er hele §05.
04 · Varianter

Fire smaker av 2PL

VariantNår slippes låser?Egenskaper
Basic 2PL Når som helst etter peak — så lenge regelen holder. Conflict-serializable. Ikke nødvendigvis cascadeless.
Conservative 2PL Alle låser tas på forhånd, før første operasjon. Deadlock-fri (alle Tx venter eller starter), men dårlig samtidighet.
Strict 2PL X-låser holdes til commit/abort. S-låser kan slippes tidligere. Conflict-serializable + strict schedule. Standard i praksis.
Rigorous 2PL Alle låser holdes til commit/abort. Enklest å implementere. Litt mindre samtidighet enn strict.

I praksis bruker de fleste databaser strict 2PL eller rigorous 2PL — fordi de gjør recovery (gjenoppretting etter krasj — kapittel 8C) enkel (undo via before-image fungerer). Basic 2PL er teoretisk korrekt, men gir cascading aborts.

Profilene visualisert

Hver variant har en distinkt form når man plotter antall holdte låser over tid. Den blå kurven er låstellet; den brune prikken merker commit:

Basic 2PL

tid → låser peak c
Klassisk fjell. Låser kan slippes når som helst etter peak — også før commit. Andre kan derfor lese uncommitted skrivinger ⇒ cascading aborts mulig.

Conservative 2PL

tid → låser vent alle låser tatt på forhånd c
Vertikalt sprang i starten: alle låser anskaffes før første operasjon. Ingen vokse-fase ⇒ ingen sirkulær venting ⇒ deadlock-fri. Pris: dårlig samtidighet.

Strict 2PL

tid → låser S sluppet X til c c
S-låser kan slippes gradvis etter peak; X-låser holdes på et platå helt til commit (vertikalt fall ved c). Ingen kan lese uncommitted ⇒ cascadeless. Standard i praksis.

Rigorous 2PL

tid → låser alle låser holdes c
Trapesform: ingen lås slippes før commit. Hele «fjellet» raser ned vertikalt ved c. Enklest å implementere — litt mindre samtidighet enn strict på lese-tunge laster.

Gjennomgått eksempel — rigorous 2PL i sekvens

Vi setter låser med rigorous 2PL for følgende sekvens som kommer inn til databasen, og finner ut i hvilken rekkefølge transaksjonene committer:

r1(A); r2(A); w1(A); r3(B); c1; w2(B); c2; r3(C); c3;

Regel ved blokkering: hvis en transaksjon blokkeres på en lås, settes alle dens videre operasjoner på vent — neste operasjon i sekvensen utføres som vanlig. (Dette er hva pensumnotatet kaller «de neste operasjonene i historien blir utført i sekvens».)

#OpLås-handlingStatus
1r1(A)T1 tar S(A)OK
2r2(A)T2 tar S(A)OK — S+S kompatibelt
3w1(A)T1 ber om X(A)Blokkert — T2 holder S(A)
4r3(B)T3 tar S(B)OK
5c1T1 vil committePå vent — w1(A) henger
6w2(B)T2 ber om X(B)Blokkert — T3 holder S(B)
7c2T2 vil committePå vent — w2(B) henger
8r3(C)T3 tar S(C)OK
9c3T3 committerSlipper S(B), S(C). Kjeden ruller videre →
T2 får X(B), kjører w2(B), så c2: T2 committerSlipper S(A), X(B)
T1 får X(A), kjører w1(A), så c1: T1 committerSlipper S(A), X(A)

Commit-rekkefølge: T3 → T2 → T1. Det er motsatt rekkefølge av hvordan de først dukket opp i sekvensen — typisk for kjeder av blokkeringer: den siste i kjeden er ikke blokkert av noen og frigjør de andre én etter én.

Slik løser du oppgavetypen

1) Tegn en kolonne per dataelement og før «Holdes av» løpende. 2) For hver operasjon: er låsen kompatibel? Hvis nei — sett operasjonen og alle påfølgende fra samme transaksjon på vent. 3) Etter siste eksplisitte operasjon: simulér frigjøringene i den rekkefølgen blokkerte transaksjoner kan rulle videre. 4) Hvis to transaksjoner gjensidig venter — vranglås.

Bla gjennom kortene under for å sjekke at du skiller variantene fra hverandre — og at du kan lese rigorous-2PL-eksempler.

Tastatur: forrige · neste · Enter/Space snu kort
1 / 0
2PL-varianter · strict vs rigorous Lett

Hva er forskjellen mellom strict og rigorous 2PL?

  • A Strict tar låser én og én; rigorous tar alt på forhånd
  • B Strict slipper S-låser tidlig men holder X-låser til commit; rigorous holder alle låser til commit
  • C Strict bruker bare X-låser; rigorous bruker både S og X
  • D De er identiske — ulike navn for samme konsept

Riktig: B.

Begge holder X-låser til commit/abort (gir strict schedule + cascadeless), men strict 2PL kan slippe S-låser tidligere mens rigorous holder alle låser til commit. Rigorous er enklere å implementere; strict gir litt mer samtidighet på lese-tunge arbeidsmengder.

2PL-varianter · deadlock-fri Middels

Hvilken 2PL-variant kan aldri havne i deadlock?

  • A Basic 2PL
  • B Strict 2PL
  • C Conservative 2PL
  • D Rigorous 2PL

Riktig: C — Conservative 2PL.

Conservative 2PL ber om alle låser før transaksjonen begynner. Hvis noen er opptatt, venter T-en før den har tatt noen lås selv — derfor kan ingen sirkulær venting oppstå.

Prisen er dårlig samtidighet og at man må vite alle låser på forhånd. De andre variantene tar låser etterhvert og kan derfor havne i sykel i wait-for-grafen.

2PL-varianter · cascading aborts Middels

Hvilken 2PL-variant er teoretisk korrekt, men kan likevel gi cascading aborts?

  • A Basic 2PL
  • B Strict 2PL
  • C Rigorous 2PL
  • D Ingen — 2PL hindrer alltid cascading aborts

Riktig: A — Basic 2PL.

Basic 2PL gir conflict-serializability, men kan slippe X-låser før commit. Det betyr at en annen transaksjon kan lese den uncommitted verdien — og hvis den første aborter, må alle som leste fra den også abortes (cascade).

Strict og rigorous holder X-låser til commit/abort, så ingen kan lese uncommitted verdier ⇒ ingen cascading aborts.

Rigorous 2PL · commit-rekkefølge Vanskelig

Sett rigorous 2PL for sekvensen r1(X); w2(X); w3(Y); r1(Y); c1; c2; c3;. I hvilken rekkefølge committer T1, T2, T3?

  • A T1; T2; T3
  • B T1; T3; T2
  • C T3; T1; T2
  • D Vranglås mellom T1 og T2

Riktig: C — T3; T1; T2.

r1(X): T1 tar S(X). w2(X): T2 ber om X(X), blokkert av T1. w3(Y): T3 tar X(Y). r1(Y): T1 ber om S(Y), blokkert av T3. c1, c2: begge på vent.

c3: T3 committer, slipper X(Y). T1 får S(Y), kjører r1(Y), commiter c1 — slipper S(X), S(Y). T2 får X(X), commiter c2.

Rigorous 2PL · uten kjede Middels

Sekvens med rigorous 2PL: r1(A); r2(B); w1(A); c1; w2(B); c2;. I hvilken rekkefølge committer T1 og T2?

  • A T2; T1 — fordi T2 starter sist
  • B T1; T2 — ingen blokkeringer
  • C Begge venter — vranglås
  • D Avhenger av scheduler-rekkefølgen

Riktig: B — T1; T2.

T1 og T2 jobber på ulike dataelementer (A og B), så ingen blokkerer. r1(A) → S(A); r2(B) → S(B); w1(A) → T1 kan oppgradere til X(A) fordi den er eneste S-holder. c1: T1 commiter, slipper låser. w2(B) → T2 oppgraderer til X(B). c2: T2 commiter.

Hovedpoenget: rigorous 2PL stenger bare ute samtidige tilganger til samme element.

05 · Deadlock

Når begge venter på hverandre

Prisen for låser: noen ganger venter to transaksjoner på hverandre samtidig. Klassisk eksempel:

(Notasjon: read_lock(X) = «be om S-lås på X», write_lock(X) = «be om X-lås på X». ✓ betyr lås tildelt.)

Steg
T1
T2
1
read_lock(X) ✓
·
2
·
read_lock(Y) ✓
3
write_lock(Y) — venter på T2
·
4
·
write_lock(X) — venter på T1
5
⌛ deadlock
⌛ deadlock

Wait-for-graf

Tegn en kant Ti → Tj hvis Ti venter på en lås Tj holder. Sykel ⇔ deadlock.

T1 T2 venter på Y venter på X
Sykel i wait-for-grafen ⇒ deadlock. Eneste vei ut: abort en av transaksjonene.

Tre strategier

  1. Forebygging (unngåelse) — conservative 2PL (alle låser opp foran), eller rangér ressurser globalt så alle tar låser i samme rekkefølge.
  2. Deteksjon + offer — periodisk sjekk wait-for-grafen; finn sykel; abort en transaksjon (ofte den yngste eller den som har gjort minst).
  3. Timeout — om en transaksjon ikke fullfører innen X sekunder, abort. Enkelt, men vanskelig å sette gode timeouts.

De fleste kommersielle systemer (PostgreSQL, MySQL/InnoDB) bruker en kombinasjon av deteksjon og timeout.

Lock upgrade — en stille deadlock-felle

Pensum nevner at låser kan oppgraderes (read_lock → write_lock) og nedgraderes. En typisk oppskrift: T1 leser X (tar read_lock(X)), regner litt, og bestemmer seg for å skrive — den ber om oppgradering til write_lock(X). Men hvis T2 også holder read_lock(X) og samtidig ber om oppgradering, sitter begge og venter på at den andre skal slippe sin S-lås — deadlock:

T1: read_lock(X) ........... write_lock(X)  ← venter på T2
T2: ......... read_lock(X) . write_lock(X)  ← venter på T1
                                  DEADLOCK

Begge T-ene følger 2PL korrekt. Likevel havner de i sykel — dette er en vanlig årsak til deadlock i praksis selv når ingen «øyeblikkelig» konflikt foreligger ved den initielle låsingen.

Sjekk · Deadlock
Hvilken 2PL-variant garanterer at deadlocks aldri oppstår?
AStrict 2PL
BRigorous 2PL
CConservative 2PL
DBasic 2PL
Conservative. Ved at alle låser tas før transaksjonen begynner — om noen er opptatt, venter T-en før den i det hele tatt har startet, uten å holde noe selv. Dermed kan ikke en sirkulær venting oppstå. Prisen er at samtidigheten lider og at det er vanskelig å vite hvilke låser som trengs på forhånd.
Sjekk · Lock upgrade
T1 og T2 holder begge S-lås på X. T1 ber om oppgradering til X-lås på X. Like etter ber T2 også om oppgradering til X-lås på X. Hva skjer?
AT1 får X-låsen først fordi den ba først; T2 venter til T1 er ferdig
BBegge får X-låsen — S-låser er kompatible, så oppgraderingen er trygg
CDeadlock — begge venter på at den andre slipper sin S-lås
DDet er et brudd på 2PL, så låsmanageren avviser begge forespørslene
Deadlock. En oppgradering S→X krever at alle andre S-holdere har sluppet. T1 venter på T2; T2 venter på T1 — sykel i wait-for-grafen. Begge fulgte 2PL korrekt (ingen slipp før peak), men «stille» konkurrerende oppgraderinger er en klassisk deadlock-felle. (B) glemmer at X er eksklusiv. (D) er feil — oppgradering er en gyldig 2PL-operasjon i vokse-fasen.
06 · Granularitet

Hva låser vi egentlig?

Granularitet = hvor stort eller lite område én lås dekker. I 2PL-teori snakker vi om «et dataelement», men i virkeligheten har vi et hierarki av muligheter:

Database Tabell konto Tabell ordre side 1 side 2 side 3 records grov fin
Hierarki: hele DB → tabell → side → record. Grov granularitet (få store låser) = mindre overhead i låstabellen, men flere transaksjoner kniper om samme lås. Fin granularitet (mange små låser) = bedre samtidighet, men dyrere låstabell.

Pensum lister fem typer låser:

  • Postlåser — fineste granularitet, høy samtidighet, men stor låsetabell.
  • Blokklåser — én lås dekker alle records i blokken.
  • Tabellåser — coarse: én skribent stenger ute alle.
  • Range-/verdiområdelåser — låser et nøkkelintervall, brukes for å unngå fantomer.
  • Predikatlåser — låser alle rader som matcher et predikat. Også for fantomer, mer presis enn range-låser.

Moderne databaser bruker typisk post- og range-låser. Trade-off er klart: grovere granularitet ⇒ mindre metadata, men mer konkurranse om de samme låsene. Finere granularitet ⇒ mer samtidighet, men dyrere lock manager.

Sjekk · Granularitet
Hvilken låsetype trenger vi for å unngå fantomer?
APostlåser
BTabellåser
CRange-/verdiområdelåser eller predikatlåser
DBlokklåser
Range-/predikatlåser. En postlås beskytter bare eksisterende rader. En fantom oppstår når en INSERT lager en ny rad som matcher predikatet — det finnes ingen post å låse på forhånd. Range-låser låser et nøkkelintervall, predikatlåser låser «alle rader som matcher denne WHERE-en».
07 · MVCC

Multi-version concurrency control

Problem med rene låser: en read blokkerer en write og omvendt. Det betyr at en lang rapporterings-spørring kan stenge ute hele OLTP-traffikken (Online Transaction Processing — vanlige korte forretningstransaksjoner).

MVCC (også kalt snapshot isolation) løser dette ved å la hver write lage en ny versjon i stedet for å overskrive. Reads ser et konsistent øyeblikksbilde fra et bestemt tidspunkt — typisk transaksjonens starttid.

Tid → X v1=100 X v2=120 X v3=150 T_les: ser X = 100 hele tiden (snapshot ved start) w1 commit w2 commit
MVCC: X eksisterer som en kjede av versjoner. En lese-transaksjon ser den versjonen som var committed da den startet — selv om andre committer nye versjoner i mellomtiden.

Reads låser ikke writes, og writes låser ikke reads. Bare write/write-konflikter krever låsing eller (i optimistiske varianter — der vi lar transaksjoner kjøre fritt og sjekker konflikter ved commit) abort av en transaksjon ved commit hvis det er konflikt.

PostgreSQL, Oracle, SQL Server (RCSI), MySQL/InnoDB — alle bruker MVCC. Det er de-facto i moderne SQL.

Snapshot isolation i praksis

Snapshot isolation brukes av PostgreSQL, MySQL/InnoDB, Oracle, SQL Server m.fl. Moderne databaser kaller løsningen sin SNAPSHOT ISOLATION og bruker write-låser kombinert med versjonering av skrevne rader.

Sjekk · MVCC
Under snapshot isolation: T1 starter, leser X = 100. T2 oppdaterer X til 150 og committer. T1 leser X igjen — hva ser den?
AX = 100 — snapshotet fra T1s starttidspunkt
BX = 150 — siste committede verdi
CT1 må vente på T2 sin write-lås
DAvhenger av hvilken database
X = 100. Dette er hele poenget med snapshot isolation: T1 ser den versjonen som var committed da T1 startet, selv om andre committer nye versjoner i mellomtiden. Lesere blokkerer aldri skrivere, og skrivere blokkerer aldri lesere. Nye transaksjoner (startet etter T2 sin commit) ser X = 150.
08 · SQL-standard

Fire isolation levels

SQL-standarden definerer fire nivåer i henhold til hvilke anomalier som kan forekomme:

LevelDirty readUnrepeatable readPhantomTypisk implementasjon
READ UNCOMMITTEDJaJaJaIngen leselåser
READ COMMITTEDNeiJaJaX-låser, korte S-låser, eller snapshot
REPEATABLE READNeiNeiAvhengerStrict 2PL på leste rader, eller snapshot
SERIALIZABLENeiNeiNeiStrict / rigorous 2PL m. range-låser

«Nivå» = strengere lenger ned. Mer korrekthet, mindre samtidighet.

Standard vs. virkelighet

Standarden er stort sett ikke fulgt i detaljer av leverandørene:

  • Oracle har ingen «REPEATABLE READ» — SERIALIZABLE er egentlig snapshot isolation.
  • PostgreSQL sin REPEATABLE READ er snapshot isolation.
  • MySQL InnoDB sin REPEATABLE READ tillater phantoms i noen tilfeller.

Tommelfingerregel: les dokumentasjonen til din database før du stoler på navnet.

Sjekk · Isolation
Du driver et nettbutikk-system og vil unngå at én kunde leser saldoen sin to ganger og får ulike svar (selv om andre kan sette inn nye rader). Hvilket isolation level er minimum?
AREAD UNCOMMITTED
BREAD COMMITTED
CREPEATABLE READ
DSERIALIZABLE
REPEATABLE READ. Spørsmålet beskriver presist unrepeatable read. REPEATABLE READ er det laveste nivået som hindrer det. Phantoms ble eksplisitt sagt at vi tolererer, så SERIALIZABLE ville vært overkill.
09 · Oppsummering

Kort oppsummert

  • Klassiske anomalier: dirty read, dirty write, unrepeatable read, incorrect summary, phantom.
  • S/X-låser + kompatibilitetsmatrise styrer tilgang.
  • 2PL (vokse-fase, krympe-fase) garanterer conflict-serializability.
  • Strict 2PL = standard i praksis: X-låser holdes til commit, gir cascadeless.
  • Deadlock = sykel i wait-for-graf. Løsninger: forebygging, deteksjon, timeout.
  • Granularitet: tabell ↔ side ↔ record. Trade-off mellom kontensjon og overhead.
  • MVCC / snapshot isolation: writers låser ikke readers og omvendt. Standard i moderne SQL.
  • SQL isolation levels: READ UNCOMMITTED → READ COMMITTED → REPEATABLE READ → SERIALIZABLE. Sjekk hva din DB faktisk leverer.

Klar for siste etappe? 8C · Recovery →