Det här är ett avsnitt i en webbkurs om databaser som finns fritt tillgänglig på adressen http://www.databasteknik.se/webbkursen/. Senaste ändring: 18 juli 2005.

Av Thomas Padron-McCarthy. Copyright, alla rättigheter reserverade, osv. Skicka gärna kommentarer till webbkursen@databasteknik.se.

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: 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).

Konsistens

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.

Commit och Abort

När en transaktion har påbörjats så finns det tre sätt att avsluta den: 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:

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):

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


Webbkursen om databaser av Thomas Padron-McCarthy.