CodeGym /Corsi /SQL SELF /Livello di isolamento SERIALIZABLE: isolame...

Livello di isolamento SERIALIZABLE: isolamento totale e prevenzione di Phantom Read

SQL SELF
Livello 40 , Lezione 2
Disponibile

SERIALIZABLE è il livello massimo di isolamento delle transazioni in PostgreSQL. Questo livello garantisce che i risultati delle transazioni parallele saranno gli stessi come se fossero eseguite IN SEQUENZA, una dopo l’altra. Nessuna anomalia di esecuzione parallela (tipo Dirty Read, Non-Repeatable Read, Phantom Read) può succedere.

In parole povere, SERIALIZABLE mette ordine totale e coerenza tra le transazioni parallele. È come se PostgreSQL dicesse: "Tutti in fila, ragazzi!"

Perché serve il livello SERIALIZABLE? A volte vuoi essere sicuro al 100% che i tuoi dati restino sempre coerenti, anche se ci sono modifiche parallele. Immagina una scena al supermercato, dove i cassieri servono i clienti contemporaneamente. Se nessuno controllasse la fila, alla fine ci sarebbero più prodotti fuori dal negozio di quanti ne sono stati acquistati. Con SERIALIZABLE una cosa del genere è semplicemente impossibile.

Esempio di impostazione del livello SERIALIZABLE

Per impostare il livello di isolamento SERIALIZABLE, usa il comando:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Per esempio, creiamo una transazione che usa questo livello:

BEGIN; -- Inizio transazione
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- Impostiamo il livello di isolamento
SELECT * FROM products WHERE category = 'Electronics'; -- Prendiamo la lista dei prodotti
UPDATE products SET stock = stock - 1 WHERE product_id = 123; -- Aggiorniamo lo stock
COMMIT; -- Confermiamo le modifiche

Case: prenotazione biglietti al cinema

Dai, vediamo un esempio reale dove il livello SERIALIZABLE è proprio fondamentale. Immagina che stai sviluppando un sistema di prenotazione online dei biglietti per il cinema. Gli utenti scelgono i posti e tu vuoi garantire che lo stesso posto non venga venduto a due clienti contemporaneamente.

Prima creiamo una tabella per i posti:

CREATE TABLE seats (
    seat_id SERIAL PRIMARY KEY,
    is_booked BOOLEAN DEFAULT FALSE
);

Ora aggiungiamo qualche posto:

INSERT INTO seats (is_booked) VALUES (FALSE), (FALSE), (FALSE);

Ecco un esempio di transazione con SERIALIZABLE.

Così puoi fare una prenotazione sicura di un posto:

BEGIN; -- Inizio transazione
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- Livello di isolamento SERIALIZABLE

-- Controlliamo che il posto sia libero
SELECT is_booked FROM seats WHERE seat_id = 1;

-- Prenotiamo il posto
UPDATE seats SET is_booked = TRUE WHERE seat_id = 1;

COMMIT; -- Confermiamo la prenotazione

Se una seconda transazione parallela prova a prenotare lo stesso posto, PostgreSQL non farà confusione e lancerà un errore di conflitto di serializzazione.

Prevenzione di Phantom Read

Ora vediamo le "letture fantasma", da cui volevamo liberarci. Phantom Read succede quando una transazione vede cambiamenti nei dati aggiunti da un’altra transazione mentre è ancora in corso. Per esempio, la tua transazione si aspetta un certo numero di righe, ma all’improvviso un’altra transazione aggiunge o cancella righe, cambiando i risultati.

Guarda l’esempio:

Dati prima dell’inizio delle transazioni

id balance user
1 1000 Alice
2 500 Bob

Transazione 1

BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- Conta gli utenti con saldo maggiore di 400
SELECT COUNT(*) FROM accounts WHERE balance > 400;

-- Ci aspettiamo: 2 (Alice e Bob)

Transazione 2

In un’altra sessione parte una transazione parallela:

BEGIN;
INSERT INTO accounts (id, balance, user) VALUES (3, 700, 'Charlie');
COMMIT;

Torniamo alla Transazione 1

-- Ripetiamo la query
SELECT COUNT(*) FROM accounts WHERE balance > 400;

Ora, se non usi SERIALIZABLE, il risultato sarà 3 invece di 2, perché Charlie è stato aggiunto mentre la Transazione 1 era ancora attiva. Questo è proprio il Phantom Read.

Ma con SERIALIZABLE PostgreSQL garantisce che la Transazione 1 non vedrà Charlie, perché la sua "visione del mondo" è congelata al momento dell’inizio della transazione.

Caratteristiche e limiti del livello SERIALIZABLE

Abbiamo visto come SERIALIZABLE ti aiuta ad avere isolamento perfetto. Ma cosa c’è di perfetto senza qualche difetto? Parliamoci chiaro.

Prestazioni più basse
SERIALIZABLE richiede molte più risorse rispetto ai livelli READ COMMITTED o REPEATABLE READ. Perché? PostgreSQL deve simulare l’esecuzione in sequenza delle operazioni, controllando tutti i possibili conflitti tra le transazioni.

Errori di serializzazione
Se PostgreSQL vede che non può eseguire le transazioni in "sequenza perfetta", genera un errore di serializzazione (serialization_failure) e fa il rollback della transazione.

Esempio di errore:

ERROR: could not serialize access due to concurrent update

Per gestire queste situazioni, puoi rilanciare la transazione dopo il fallimento:

DO $$
DECLARE
    done BOOLEAN := FALSE;
BEGIN
    WHILE NOT done LOOP
        BEGIN
            -- Inizio transazione
            BEGIN;
            SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

            -- Facciamo le operazioni
            UPDATE accounts SET balance = balance - 100 WHERE id = 1;

            -- Confermiamo le modifiche
            COMMIT;
            done := TRUE; -- Esci dal ciclo se tutto ok
        EXCEPTION WHEN serialization_failure THEN
            ROLLBACK; -- Rollback in caso di errore
        END;
    END LOOP;
END;
$$;

Questo è il modo classico nei sistemi dove si usa SERIALIZABLE.

Importante!

Questo codice è scritto usando PL-SQL. Ci torneremo più avanti. Volevo solo darti un esempio bello e funzionante. E anche farti vedere a cosa serve PL-SQL :)

Quando usare SERIALIZABLE?

Questo livello di isolamento ha senso dove l’errore costa caro:

  • Transazioni finanziarie, tipo gestione pagamenti o distribuzione di bonus.
  • Sistemi di gestione delle scorte, per evitare ordini doppi.
  • Prenotazioni online, dove è fondamentale evitare conflitti sulle risorse.

Se stai sviluppando un sistema dove i dati devono essere coerenti al 100% e le prestazioni non sono la priorità, SERIALIZABLE sarà il tuo migliore amico.

2
Compito
SQL SELF, livello 40, lezione 2
Bloccato
Prevenire la doppia prenotazione
Prevenire la doppia prenotazione
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION