Det här är ett avsnitt i en
webbkurs om databaser.
Skicka gärna kommentarer eller frågor
till författaren,
särskilt om du hittar fel eller oklarheter.
Transaktioner
När man arbetar med en databas, i synnerhet när man gör ändringar i databasen,
är det ofta så att en följd av operationer hör ihop som en enhet.
Ett exempel kan vara att flytta pengar från ett bankkonto till ett annat.
Då drar man först bort beloppet från det ena kontot,
och adderar det sen till det andra kontot.
En sådan följd av operationer som hör ihop kallas en transaktion.
De flesta databashanterare har inbyggda mekanismer för att underlätta
transaktioner. Man kan, med särskilda kommandon,
tala om för databashanteraren att en viss följd av operationer
hör ihop och utgör en transaktion.
ACID-transaktioner
Man brukar tala om ACID-transaktioner.
Bokstäverna i ACID anger fyra egenskaper som transaktioner bör ha,
och som man vill att databashanteraren automatiskt ska garantera:
Faktaruta
om ordet "konsistens":
Jag använder "konsistens" som en översättning av
engelskans "consistency". "Consistency" betyder ungefär
"utan inre motsägelser",
och kan översättas med "konsekvens" eller "logisk koherens".
En del språkvårdare hävdar med stor bestämdhet
att man på svenska ska använda just "konsekvens" eller "koherens",
och inte "konsistens".
Det svenska ordet "konsistens", påpekar de,
handlar inte om databaser utan om hur lättflytande vaniljsåsen är.
Jag har valt att ignorera språkvårdarna,
och skriver i fortsättningen glatt "konsistens".
Om inte annat så kan det påminna oss om att det är en teknisk term
med en ganska specifik betydelse, och inte vilken sorts
"konsekvens" eller "koherens" som helst.
I databassammanhang brukar konsistens betyda att
alla integritetsvillkor
ska vara uppfyllda.
Alla data i databasen ska alltså följa integritetsvillkoren.
Något annat skulle ju vara just en inre motsägelse, eftersom
integritetsvillkoren i så fall skulle säga en sak, och de data
som bryter mot dem skulle säga en annan.
Man brukar också räkna in databasens interna datastrukturer i konsistensen.
Till exempel måste ett index
stämma överens med den riktiga tabell som det pekar in i.
Om man lägger till eller tar bort rader i tabellen,
och indexet av någon anledning inte ändras för att reflektera detta,
så kan databashanteraren kanske bli så förvirrad att den kraschar.
Det är en särskilt allvarlig form av inkonsistens,
eftersom det kan göra att det man inte kommer åt några data alls i databasen.
|
- A står för atomicitet, dvs odelbarhet.
En transaktion ska vara odelbar.
Det betyder att antingen ska hela transaktionen
genomföras, så att alla ändringar den gör förs in i databasen,
eller så ska inga ändringar alls göras.
Om en transaktion avbryts mitt i (för att användaren ångrar sig,
eller för att strömmen går, eller vad det nu kan bero på),
måste databashanteraren alltså ta bort alla ändringar som den hunnit göra.
- C står för consistency preserving,
dvs "konsistensbevarande". Om databasen är konsistent,
dvs utan några inre motsägelser, före en transaktion,
så ska den också vara konsistent efter transaktionen.
Det här betyder att databashanteraren måste kontrollera
alla integritetsvillkor,
så att de är uppfyllda.
- I står för isolering.
Transaktionerna ska hållas isolerade från varandra.
Även om databashanteraren utför flera transaktioner samtidigt
så får en transaktion aldrig se en annan
transaktions halvfärdiga ändringar.
(Något förenklat. I en del system är det lite krångligare än så.)
- D står för durability, dvs "hållbarhet".
När transaktionen är genomförd och avslutad ska de ändringar den gjort
aldrig försvinna ur databasen,
även om strömmen går, om datorn kraschar,
och helst också om disken går sönder.
De flesta relationsdatabashanterare, men inte alla,
har den här transaktionshanteringen inbyggd.
Till exempel är
MySQL
känd för att inte ha transaktionshantering
(även om det går att åstadkomma i nyare versioner).
Commit och Abort
När en transaktion har påbörjats så finns det tre sätt att avsluta den:
- Commit
- Abort (även kallat "rollback")
- En krasch av något slag
Commit betyder att användaren, vare sig den "användaren"
är en person som sitter och skriver SQL-kommandon
eller ett program som arbetar med databasen,
anser sig vara färdig, och talar om det för databashanteraren.
I SQL kan man använda kommandot COMMIT.
Databashanteraren måste nu se till att alla ändringar verkligen
sparas ordentligt (tänk på D:et, "hållbarhet", i ACID)
och att databasen är konsistent (C:et, "konsistensbevarande", i ACID).
Abort (även kallat "rollback")
betyder att användaren
(som fortfarande kan vara en människa eller ett program)
har ångrat sig och vill avbryta transaktionen.
Det kan till exempel bero på att användaren upptäckt att det
inte finns tillräckligt med pengar på bankkontot för att göra
den där överföringen.
I SQL kan man använda kommandot ABORT
(som ibland stavas ROLLBACK).
Om det gjorts några ändringar i databasen,
så måste databashanteraren nu ändra tillbaka till hur det såg ut
före transaktionen (A:et, "atomicitet", i ACID).
Notera att databashanteraren själv kan bestämma sig för att
avbryta en transaktion. Antag till exempel att användaren vill
"committa" en transaktion, och databashanteraren då upptäcker att
användaren gjort ändringar i databasen som strider mot
integritetsvillkoren, och som därför inte är tillåtna.
Då kan databashanteraren behöva avbryta transaktionen,
och ändra tillbaka de ändringar som gjorts i databasen.
Krascher och återstarter
Transaktionen kan också avbrytas av en krasch av något slag,
till exempel om strömmen går eller datorn kraschar.
När man sen startar datorn, och databashanteraren, igen,
så ser databasen som finns på disken ut precis som den såg ut
i kraschögonblicket. Den kan alltså innehålla
en eller flera halvfärdiga transaktioner,
som höll på att köras när kraschen inträffade.
Det kan dels vara sådana transaktioner som avbröts mitt i,
men som hann med att göra en del av sina ändringar i databasen,
och det kan också vara transaktioner som egentligen är avslutade,
men där alla ändringarna inte hann skrivas på disken.
Detta strider mot både A:et (atomicitet) och D:et (hållbarhet) i ACID.
För att råda bot på detta genomför databashanteraren
en återhämtning (recovery på engelska).
Under återhämtningen måste alla halvfärdiga transaktioner åtgärdas:
-
Avbrutna transaktioner, som inte räknas som klara, ska tas bort.
Det betyder att om de hunnit göra några ändringar i databasen,
så ska de ändras tillbaka.
-
Transaktioner som räknas som klara måste också kontrolleras.
Om dessa transaktioner gjort ändringar som inte hunnit skrivas på disken,
så måste de skrivas på disken nu.
På det här viset kan databashanteraren alltså klara att
man drar ur strömsladden till datorn, utan att några data
går förlorade.
Det går förstås att göra samma sak själv när man skriver
ett program (för databashanteraren är ju ett program den också),
men det är ganska krångligt att få det rätt.
Loggfilen
Databashanteraren måste alltså kunna ändra tillbaka saker som ändrats
i databasen. Det går att göra på flera sätt, men det vanligaste är
att man använder en särskild loggfil.
En loggbok ombord på ett skepp är ju en bok där man skriver upp allt som händer,
och en loggfil fungerar på liknande sätt.
Varje transaktion, som vill göra en ändring i databasen,
skriver först en notering om det i loggfilen.
Där står (fast det kan variera lite mellan olika databashanterare):
- vilken transaktion det är,
- vilket dataobjekt det handlar om,
- vad det gamla värdet på dataobjektet var, och
- vad det nya värdet ska bli.
Databashanteraren börjar med att skriva noteringen i loggfilen,
och först därefter görs ändringen i databasen.
(Övning: Varför? [Svar])
Detta brukar kallas write-ahead logging, ungefär "skriv-i-förväg-loggning".
Eftersom alla ändringar som gjorts i databasen, kan databashanteraren
titta i loggfilen och se vad som behöver ändras tillbaka
när en transaktion avbryts.
Reservkopior ("backup")
Vi nämnde ovan att databashanteraren helst ska klara av även
en diskkrasch utan att tappa bort några transaktioner.
Ett sätt att få det att fungera är att regelbundet göra en reservkopia,
eller "backup" som det heter på engelska, av databasen.
När disken sen går sönder sätter man i en ny, fungerande, disk i datorn,
kopierar dit databasen från reservkopian,
och låter sen databashanteraren gå igenom loggfilen
och göra alla de ändringar som finns noterade där,
sen den tidpunkt då reservkopian gjordes.
Det här förutsätter att vi inte har placerat loggfilen och själva databasen
på samma hårddisk, för om vi gjort det så blir det förstås svårt.
(Det finns också ett annat skäl till att ha loggfilen och databasen
på olika diskar, nämligen prestanda.
Eftersom alla ändringar ska noteras i loggfilen,
innebär det att varje ändring i databasen leder till att vi skriver
på disken två gånger: en gång för att göra noteringen i loggfilen,
och en gång för att göra själva ändringen.
Det brukar vara just kommunikationen med hårddisken som är
flaskhalsen i en databashanterare, och genom att lägga loggfilen
och databasen på varsin disk, kan skrivningar till båda diskarna
ske samtidigt, och alltså kan systemet arbeta dubbelt så fort.)
I:et i ACID: Isolering
Transaktionerna ska hållas isolerade från varandra.
Även om databashanteraren utför flera transaktioner samtidigt
så får en transaktion aldrig se en annan
transaktions halvfärdiga ändringar.
Detta kan databashanteraren åstadkomma på flera sätt,
men det vanligaste är att man använder olika typer av lås.
När en transaktion vill arbeta med ett dataobjekt i databasen,
till exempel behållningen på ett bankkonto, låser transaktionen
det dataobjektet. Nu får ingen annan transaktion
göra något med dataobjektet.
Om en annan transaktion också vill arbeta med dataobjektet, får den vänta
tills den första transaktionen är färdig och släpper låset.
Då kan nästa transaktion låsa objektet.
De viktigaste begreppen
De viktigaste begreppen från det här avsnittet finns också med i
ordlistan:
transaktion,
ACID,
commit,
abort
(eller rollback),
återhämtning
(recovery på engelska),
loggfil,
lås,
konsistens,
inkonsistens
Litteratur
Av Thomas Padron-McCarthy
(e-post: tpm@ida.liu.se).
Copyright,
alla rättigheter reserverade, osv.
Senaste ändring:
6 juli 2002