In SQL, le transazioni permettono di raggruppare diverse operazioni (insert/update/delete) in un'unica unità atomica di lavoro che può essere applicata completamente o annullata. Il ciclo di vita di una transazione è basato su comandi:
BEGIN o START TRANSACTION — inizio della transazione;COMMIT — conferma delle modifiche;ROLLBACK — annullamento di tutte le modifiche all'interno della transazione.SQL supporta livelli di isolamento delle transazioni (Read Uncommitted, Read Committed, Repeatable Read, Serializable), che definiscono la visibilità dei dati tra transazioni parallele e proteggono da problemi come "letture sporche" o "righe fantasma".
Per controllare l'integrità dei dati sono necessari:
SELECT ... FOR UPDATE).Esempio in PostgreSQL:
BEGIN; -- Otteniamo e blocchiamo la riga del prodotto SELECT * FROM inventory WHERE id = 1 FOR UPDATE; UPDATE inventory SET quantity = quantity - 1 WHERE id = 1; COMMIT;
Qual è il livello di isolamento predefinito impostato nei popolari DBMS (PostgreSQL, MySQL) e in cosa differisce da SERIALIZABLE?
Risposta:
In PostgreSQL, per impostazione predefinita, si utilizza il livello Read Committed — in esso la transazione vede solo i dati confermati al momento della richiesta, ma sono possibili "letture non ripetibili" (non-repeatable reads).
In MySQL (InnoDB) — Repeatable Read. La differenza rispetto a Serializable è che solo quest'ultimo previene completamente qualsiasi modifica fantasma o parallela, ma funziona notevolmente più lentamente a causa dei blocchi globali.
Esempio:
-- In Repeatable Read, SELECT può restituire le stesse righe, mentre in Read Committed possono apparire nuove righe tra due SELECT all'interno della transazione.
Storia
In un grande sistema finanziario, durante massicce transazioni tra conti a un basso livello di isolamento (Read Committed), si verificavano periodicamente situazioni in cui lo stesso saldo veniva utilizzato simultaneamente da più transazioni. Questo portava a una doppia spesa di fondi (race condition). Dopo il passaggio a
Serializablee una gestione corretta dei blocchi, il problema è scomparso.
Storia
Nell'e-commerce, una transazione con
UPDATE product SET stock = stock - 1senza essere racchiusa in una transazione portava alla vendita di più beni di quanti ce ne fossero in magazzino. Il problema si è manifestato solo con un gran numero di ordini concorrenti. Soluzione: utilizzare transazioni e blocco delle righe tramiteSELECT ... FOR UPDATE.
Storia
In un sistema logistico, in una delle tabelle, durante aggiornamenti frequenti, si dimenticò di effettuare un commit esplicito. In caso di errori, parte dei dati veniva persa a causa di autocommit o rollback errati. Risultato: perdita di record e costosi audit.