ProgrammazioneSviluppatore Backend

Racconta in dettaglio le specifiche di lavoro con le transazioni in SQL. Come controllare l'integrità dei dati durante l'accesso simultaneo a una stessa tabella da diverse sessioni?

Supera i colloqui con l'assistente IA Hintsage

Risposta

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:

  • Una corretta scelta del livello di isolamento (ad esempio, per applicazioni bancarie è probabile che si utilizzi Serializable).
  • Gestione esplicita delle transazioni, soprattutto dove una entità viene modificata simultaneamente (ad esempio, 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;

Domanda trabocchetto

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 Serializable e una gestione corretta dei blocchi, il problema è scomparso.


Storia

Nell'e-commerce, una transazione con UPDATE product SET stock = stock - 1 senza 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 tramite SELECT ... 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.