Transaction Isolation Levels
TeoriForskellige niveauer af isolation mellem samtidige transaktioner der balancerer konsistens mod ydeevne.
Beskrivelse
Transaktions-isolationsniveauer definerer graden af isolation mellem samtidige transaktioner - hvor meget én transaktion kan se af en andens ucommittede eller committede ændringer. SQL-standarden definerer fire isolationsniveauer, hver med forskellige afvejninger mellem datakonsistens og ydeevne. Read Uncommitted er det laveste niveau hvor transaktioner kan læse ucommittet data fra andre transaktioner (dirty reads). Read Committed forhindrer dirty reads men tillader non-repeatable reads og phantom reads. Repeatable Read garanterer at gentagende læsninger returnerer samme data, men phantom reads kan stadig ske. Serializable er det højeste niveau der fuldstændigt isolerer transaktioner som om de kørte sekventielt, hvilket forhindrer alle anomalier men med høj ydeevneomkostning. De fleste databaser bruger Read Committed som standard fordi det giver god balance. PostgreSQL bruger en variant kaldet Snapshot Isolation. Valg af isolationsniveau afhænger af applikationskrav - finansielle systemer kræver ofte højere isolation, mens læsetunge applikationer kan acceptere lavere niveauer for bedre ydeevne.
Problem
Samtidige transaktioner kan forårsage anomalier: dirty reads (læse ucommittet data), non-repeatable reads (samme forespørgsel returnerer forskellige resultater), phantom reads (nye rækker dukker op i intervalforespørgsler), og tabte opdateringer (to transaktioner overskriver hinandens ændringer). Uden ordentlig isolation kan dataintegritet kompromitteres.
Løsning
Database-isolationsniveauer giver forskellige garantier mod disse anomalier. Højere isolationsniveauer forhindrer flere anomalier men kræver mere låsning og reducerer samtidighed. Udviklere vælger isolationsniveau baseret på applikationsbehov - hvor vigtig er konsistens vs. ydeevne?
Eksempel
-- SQL: Sæt isolation level
-- Read Uncommitted (lavest isolation)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION;
SELECT * FROM accounts WHERE id = 123;
-- Kan se uncommitted changes fra andre transactions (dirty read)
COMMIT;
-- Read Committed (default i de fleste databaser)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 123; -- Ser 1000
-- Anden transaction ændrer balance til 500 og committer
SELECT balance FROM accounts WHERE id = 123; -- Ser 500 (non-repeatable read)
COMMIT;
-- Repeatable Read
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 123; -- Ser 1000
-- Anden transaction ændrer balance til 500 og committer
SELECT balance FROM accounts WHERE id = 123; -- Ser stadig 1000
-- Men phantom reads kan stadig ske:
SELECT * FROM accounts WHERE balance > 100; -- Ser 5 rows
-- Anden transaction indsætter ny account
SELECT * FROM accounts WHERE balance > 100; -- Kan se 6 rows
COMMIT;
-- Serializable (højest isolation)
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT * FROM accounts WHERE balance > 100;
-- Ingen andre transactions kan ændre data der påvirker dette query
-- Helt isoleret som om transactions kører sekventielt
COMMIT;
-- Anomaly eksempler
-- 1. Dirty Read (kun muligt i Read Uncommitted)
-- Transaction 1:
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 123;
-- Ikke committed endnu
-- Transaction 2 (READ UNCOMMITTED):
SELECT balance FROM accounts WHERE id = 123; -- Ser 500 (dirty!)
-- Transaction 1:
ROLLBACK; -- Balance er tilbage til original værdi
-- Transaction 2 læste data der aldrig blev committed!
-- 2. Non-Repeatable Read (muligt i Read Committed)
-- Transaction 1:
BEGIN;
SELECT balance FROM accounts WHERE id = 123; -- Ser 1000
-- Transaction 2:
UPDATE accounts SET balance = 500 WHERE id = 123;
COMMIT;
-- Transaction 1:
SELECT balance FROM accounts WHERE id = 123; -- Ser nu 500!
COMMIT;
-- 3. Phantom Read (muligt i Repeatable Read)
-- Transaction 1:
BEGIN;
SELECT COUNT(*) FROM accounts WHERE balance > 100; -- 10 accounts
-- Transaction 2:
INSERT INTO accounts (balance) VALUES (200);
COMMIT;
-- Transaction 1:
SELECT COUNT(*) FROM accounts WHERE balance > 100; -- Nu 11 accounts!
COMMIT;
-- PostgreSQL eksempel
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- Query data
SELECT * FROM products WHERE stock > 0;
-- Concurrent inserts vil ikke ses (no phantom reads i Postgres)
COMMIT;
-- MySQL/InnoDB eksempel
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT SUM(balance) FROM accounts;
-- Fuldstændig isoleret
COMMIT;
-- Node.js eksempel
const { Pool } = require('pg');
const pool = new Pool();
const client = await pool.connect();
try {
await client.query('BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE');
const result = await client.query(
'SELECT stock FROM products WHERE id = $1',
[productId]
);
const stock = result.rows[0].stock;
if (stock >= quantity) {
await client.query(
'UPDATE products SET stock = stock - $1 WHERE id = $2',
[quantity, productId]
);
await client.query('COMMIT');
} else {
await client.query('ROLLBACK');
throw new Error('Insufficient stock');
}
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
-- Isolation Level Comparison Table
-- Level | Dirty Read | Non-Repeatable | Phantom | Performance
-- Read Uncommitted | Possible | Possible | Possible| Højest
-- Read Committed | Prevented | Possible | Possible| Høj
-- Repeatable Read | Prevented | Prevented | Possible| Medium
-- Serializable | Prevented | Prevented | Prevented| LavestFordele
- ✓Kontrol over konsistens vs. ydeevne-afvejning
- ✓Forhindrer dataanomalier
- ✓Fleksibilitet til forskellige anvendelser
- ✓Standard på tværs af databaser (SQL-92)
- ✓Forudsigelig adfærd
Udfordringer
- ⚠Højere isolation = lavere samtidighed
- ⚠Deadlocks mere sandsynlige ved høj isolation
- ⚠Ydeevnepåvirkning af låsning
- ⚠Forskellige implementationer på tværs af databaser
- ⚠Kompleksitet i valg af rigtigt niveau
Anvendelsesområder
- •Finansielle transaktioner (Serializable)
- •Rapportering og analyse (Read Committed)
- •Lageropdateringer (Repeatable Read)
- •Læsetunge dashboards (Read Uncommitted)
- •Bookingsystemer (Serializable)
Eksempler fra den virkelige verden
- •Bankoverførsler bruger Serializable eller Repeatable Read
- •E-handels lageropdateringer bruger Repeatable Read
- •Analyse-dashboards kan bruge Read Committed
- •Bookingsystemer (fly) bruger Serializable
- •Sociale medie-feeds kan bruge Read Committed