En transaktion är en logisk enhet av arbete — en eller flera operationer som exekveras som en helhet. Antingen utförs alla operationer, eller ingen.


ACID

EgenskapBetydelse
AtomicityAllt eller inget — transaktionen är odelbar
ConsistencyDatabasen går från ett giltigt tillstånd till ett annat
IsolationSamtidiga transaktioner påverkar inte varandra
DurabilityResultatet är permanent även vid systemkrasch

Atomicity — odelbarhet

Antingen utförs hela transaktionen, eller så rullas allt tillbaka (ROLLBACK).

BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
-- Om något går fel här (t.ex. id = 2 finns inte)
-- rullas den första UPDATE:n också tillbaka
COMMIT;

Databasen använder Write-Ahead Logging (WAL) — alla ändringar loggas först, sedan skrivs de till disk. Vid en krasch kan återställning göras från loggen.


Consistency — konsekvens

Databasen är i ett konsekvent tillstånd före och efter transaktionen. Alla regler, constraints, triggers och kaskader upprätthålls.

CREATE TABLE accounts (
  id      INT PRIMARY KEY,
  owner   VARCHAR(100),
  balance DECIMAL(10,2) CHECK (balance >= 0) -- Saldo får inte bli negativt
);

BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
-- Om detta gör balance < 0 bryts CHECK-constraintet
-- och transaktionen rullas tillbaka
COMMIT;

Isolation — isolering

Isolation definierar hur samtidiga transaktioner interagerar. Problemen som kan uppstå:

ProblemBeskrivning
Dirty ReadLäser data från en icke-committad transaktion
Non-repeatable ReadSamma fråga ger olika svar inom samma transaktion
Phantom ReadNya rader dyker upp vid upprepad läsning
Lost UpdateTvå transaktioner skriver över varandras ändringar

Isoleringsnivåer (SQL-standard)

NivåDirty ReadNon-repeatablePhantomPrestanda
READ UNCOMMITTEDKan händaKan händaKan händaBäst
READ COMMITTEDXKan händaKan hända
REPEATABLE READXXKan hända
SERIALIZABLEXXXSämst
-- Standard i PostgreSQL och SQL Server
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- Högsta nivån — full serialisering
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(balance) FROM accounts; -- Alla frågor ser samma ögonblicksbild
UPDATE accounts SET balance = balance + 100 WHERE id = 1;
COMMIT;

PostgreSQL använder READ COMMITTED som standard och implementerar REPEATABLE READ och SERIALIZABLE via Snapshot Isolation (MVCC).


MVCC — Multi-Version Concurrency Control

De flesta moderna databaser (PostgreSQL, MySQL/InnoDB, Oracle) använder MVCC istället för låsbaserad concurrency control.

Transaktion A:          Transaktion B:
  BEGIN;                  BEGIN;
  SELECT balance → 1000   SELECT balance → 1000
  UPDATE SET balance=800  UPDATE SET balance=900
  (skapar ny version)     (väntar på A)
  COMMIT;
                          Fortsätter med versionen
                          från när B startade

Varje transaktion ser en ögonblicksbild (snapshot) av databasen från den tidpunkt transaktionen startade (eller från första frågan, beroende på nivå).


Durability — beständighet

När en transaktion är committad är data beständig — även vid strömavbrott eller systemkrasch.

WAL (Write-Ahead Logging):

  1. Ändringar skrivs till en loggfil (WAL)
  2. Loggen spolas till disk (fsync)
  3. Databassidorna skrivs till disk (kan göras asynkront)

Vid återstart spelar databasen upp WAL för att återställa committade transaktioner och rulla tillbaka ej committade.


Praktiska exempel

Exempel 1: Banköverföring

BEGIN;
  UPDATE accounts SET balance = balance - 5000 WHERE id = 1;
  UPDATE accounts SET balance = balance + 5000 WHERE id = 2;
  INSERT INTO transfers (from_account, to_account, amount, created_at)
  VALUES (1, 2, 5000, NOW());
COMMIT;

Exempel 2: Pessimistisk låsning

BEGIN;
  -- Lås raden för uppdatering — ingen annan kan ändra den
  SELECT quantity FROM inventory WHERE product_id = 42 FOR UPDATE;

  IF quantity >= 10 THEN
    UPDATE inventory SET quantity = quantity - 10 WHERE product_id = 42;
    INSERT INTO orders (product_id, quantity) VALUES (42, 10);
    COMMIT;
  ELSE
    ROLLBACK;
    RAISE 'Otillräckligt lager';
  END IF;

Exempel 3: Optimistisk låsning (via version)

-- Istället för lås: använd en versionskolumn
UPDATE products
SET stock = stock - 5, version = version + 1
WHERE id = 42 AND version = 7;

-- Om versionen ändrats (rows_affected = 0) — någon annan ändrade data
-- Gör om frågan

Sammanfattning

  • ACID garanterar tillförlitlighet för transaktioner
  • Isoleringsnivåer balanserar konsekvens och prestanda
  • MVCC är standardmetoden för concurrency control i moderna databaser
  • Välj lägsta isoleringsnivån som uppfyller dina krav för bästa prestanda

Av Victor Hernandez från Bytebase.se