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
| Egenskap | Betydelse |
|---|---|
| Atomicity | Allt eller inget — transaktionen är odelbar |
| Consistency | Databasen går från ett giltigt tillstånd till ett annat |
| Isolation | Samtidiga transaktioner påverkar inte varandra |
| Durability | Resultatet ä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å:
| Problem | Beskrivning |
|---|---|
| Dirty Read | Läser data från en icke-committad transaktion |
| Non-repeatable Read | Samma fråga ger olika svar inom samma transaktion |
| Phantom Read | Nya rader dyker upp vid upprepad läsning |
| Lost Update | Två transaktioner skriver över varandras ändringar |
Isoleringsnivåer (SQL-standard)
| Nivå | Dirty Read | Non-repeatable | Phantom | Prestanda |
|---|---|---|---|---|
| READ UNCOMMITTED | Kan hända | Kan hända | Kan hända | Bäst |
| READ COMMITTED | X | Kan hända | Kan hända | |
| REPEATABLE READ | X | X | Kan hända | |
| SERIALIZABLE | X | X | X | Sä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 COMMITTEDsom standard och implementerarREPEATABLE READochSERIALIZABLEvia 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):
- Ändringar skrivs till en loggfil (WAL)
- Loggen spolas till disk (
fsync) - 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