Spiegazione di transazioni SQL e ACID: COMMIT, ROLLBACK e livelli di isolamento

  1. Home
  2. Blog
  3. Database e SQL

Database e SQL

Spiegazione di transazioni SQL e ACID: COMMIT, ROLLBACK e livelli di isolamento

Cosa succede se il server si guasta a metà del trasferimento di denaro tra due conti? Le transazioni sono la risposta. Guarda come funzionano su un esempio reale, cosa significa ACID e come scegliere un livello di isolamento.

9 min di lettura
Spiegazione delle transazioni SQL e ACID: COMMIT, ROLLBACK e livelli di isolamento

Punti chiave

  • Una transazione raggruppa le istruzioni in modo che tutte abbiano successo insieme o falliscano tutte insieme.
  • COMMIT rende permanenti le modifiche e ROLLBACK le annulla.
  • ACID sta per atomicità, consistenza, isolamento e durabilità.
  • Un isolamento più forte previene ulteriori anomalie, ma può ridurre la concorrenza, quindi sceglilo con attenzione.

Lo spostamento di 300 rupie da Asha a Ben richiede due aggiornamenti: sottrarre da un conto e aggiungere all’altro. Se il sistema tra loro fallisce, il denaro svanisce. Le transazioni SQL esistono per renderlo impossibile, trattando entrambi i passaggi come una singola unità.

In questa guida esamineremo commit, rollback ed errori su una tabella di piccoli account. Abbiamo eseguito questi esempi in SQLite e i saldi mostrati provengono da quell’esecuzione. I comandi di base sono simili tra i database, ma il comportamento di blocco e isolamento varia molto, quindi indichiamo dove controllare la documentazione del proprio database.

Cos’è una transazione?

Una transazione è una sequenza di una o più istruzioni SQL che il database considera come un’unica operazione logica. Ecco la nostra tabella:

CREATE TABLE accounts (
  id INT PRIMARY KEY,
  owner TEXT,
  balance INT CHECK (balance >= 0)
);

INSERT INTO accounts VALUES (1, 'Asha', 1000), (2, 'Ben', 200);

Il vincolo CHECK è una regola secondo cui un saldo non può mai scendere sotto lo zero, che utilizzeremo in seguito. Si noti che la sintassi per iniziare una transazione varia: SQLite e PostgreSQL accettano BEGIN, anche MySQL ha START TRANSACTION e SQL Server utilizza BEGIN TRANSACTION.

Al di fuori di una transazione esplicita, la maggior parte dei database utilizza autocommit, dove ogni istruzione viene salvata non appena termina. Oracle è un’eccezione notevole, perché una sessione rimane in una transazione fino al commit.

IMPEGNO: renderlo permanente

BEGIN;
UPDATE accounts SET balance = balance - 300 WHERE id = 1;
UPDATE accounts SET balance = balance + 300 WHERE id = 2;
COMMIT;

-- Asha | 700
-- Ben  | 500

Fino all’esecuzione di COMMIT, le modifiche sono provvisorie. Una volta restituito con successo, il database garantisce che vengano salvati. Il totale su entrambi i conti è rimasto a 1200, che è il punto centrale dell’esercizio.

ROLLBACK: annulla tutto

ROLLBACK annulla tutto dall’inizio della transazione:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
SELECT owner, balance FROM accounts;
-- Asha | 600   (visible inside this transaction)
-- Ben  | 500

ROLLBACK;
SELECT owner, balance FROM accounts;
-- Asha | 700   (back to where it was)
-- Ben  | 500

Un rollback avviene automaticamente anche se la connessione si interrompe o il server si arresta in modo anomalo prima del commit, quindi una transazione completata a metà non sopravvive.

Quando un’affermazione fallisce

Ecco un caso più realistico. Asha tenta di inviare 5000, che il conto non contiene. Il credito a Ben viene eseguito per primo, quindi l’addebito infrange la regola CHECK:

BEGIN;
UPDATE accounts SET balance = balance + 5000 WHERE id = 2;
UPDATE accounts SET balance = balance - 5000 WHERE id = 1;
-- error: CHECK constraint failed: balance >= 0

ROLLBACK;

-- Asha | 700
-- Ben  | 500

Senza la transazione, Ben avrebbe tenuto i 5000 e i libri contabili sarebbero sbagliati. Tieni presente un dettaglio importante: un’istruzione non riuscita non sempre annulla la transazione da sola. In SQLite e MySQL, ad esempio, le istruzioni precedenti possono rimanere in sospeso, quindi il codice deve eseguire il rollback. PostgreSQL invece contrassegna l’intera transazione come interrotta e rifiuta ulteriori istruzioni finché non si esegue il rollback.

Nel codice dell’applicazione, associare sempre la transazione alla gestione degli errori. Ecco l’idea in Python e la nostra guida alla gestione delle eccezioni Python spiega la sintassi:

try:
    conn.execute("BEGIN")
    conn.execute(debit_sql, values)
    conn.execute(credit_sql, values)
    conn.execute("COMMIT")
except Exception:
    conn.execute("ROLLBACK")
    raise

Punti di salvataggio

Un punto di salvataggio contrassegna una posizione all’interno di una transazione, quindi puoi annullare solo una parte del lavoro:

BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 1;
SAVEPOINT bonus;
UPDATE accounts SET balance = balance + 999 WHERE id = 2;
ROLLBACK TO bonus;
UPDATE accounts SET balance = balance + 50 WHERE id = 2;
COMMIT;

-- Asha | 650
-- Ben  | 550

Il bonus 999 è stato annullato, mentre il resto della transazione è stato portato avanti e impegnato. Ciò è utile per i passaggi facoltativi in ​​un processo lungo.

Spiegazione delle proprietà dell’ACIDO

Proprietà Promessa Nel nostro trasferimento
Atomicità Tutto o niente Entrambi gli aggiornamenti si verificano, o nessuno dei due
Coerenza Le regole valgono anche dopo Nessun equilibrio può infrangere la regola CHECK.
Isolamento Il lavoro simultaneo non interferisce Altri non vedono un trasferimento finito a metà
Durabilità I dati salvati sopravvivono al fallimento Un’interruzione di corrente dopo COMMIT non perde nulla

La coerenza è spesso fraintesa. Il database applica solo le regole dichiarate, come vincoli e chiavi esterne. Ciò non impedirà al tuo codice di trasferire l’importo sbagliato. La durabilità viene solitamente ottenuta con un registro write-ahead, in cui le modifiche vengono registrate in modo sicuro su disco prima della conferma del commit.

Cosa succede con le transazioni simultanee?

Abbiamo aperto due connessioni a un file SQLite. Il primo ha avviato una transazione e aggiornato una riga da 1 a 2, senza ancora impegnarsi. Ecco cosa ha visto la seconda connessione:

Connection B reads:   1                     -- no uncommitted data
Connection B writes:  database is locked    -- it has to wait
(A commits)
Connection B reads:   2                     -- now it sees the change

SQLite consente un solo scrittore alla volta, il che è più semplice dei database dei server, dove molte transazioni possono scrivere righe diverse contemporaneamente. Ma il principio è lo stesso: le altre sessioni non dovrebbero vedere modifiche non confermate con impostazioni normali e le scritture in conflitto devono attendere. Nel nostro test, abbiamo impostato la seconda connessione in modo che si interrompesse immediatamente invece di aspettare, quindi l’errore è apparso immediatamente.

Leggi le anomalie

Quando le transazioni si sovrappongono, possono verificarsi alcuni problemi. Lo standard SQL li definisce in termini di ciò che una transazione può osservare:

Anomalia Cosa succede
Lettura sporca Leggi una modifica di cui un’altra transazione non ha effettuato il commit e potrebbe essere successivamente ripristinata
Lettura non ripetibile Leggi una riga due volte in una transazione e ottieni valori diversi, perché qualcuno si è impegnato nel mezzo
Lettura fantasma Esegui la stessa query due volte e ottieni righe aggiuntive o mancanti, perché qualcuno ne ha inserite o eliminate alcune

Un altro problema è l’aggiornamento perso. Due sessioni leggono un saldo di 100, ciascuna aggiunge 10 e ciascuna scrive 110. Un aggiornamento è effettivamente svanito, quando la risposta dovrebbe essere 120.

Livelli di isolamento SQL

I livelli di isolamento consentono di scambiare la rigidità con la concorrenza. Ecco cosa consente lo standard SQL a ogni livello:

Livello Lettura sporca Lettura non ripetibile Lettura fantasma
Leggi senza impegno Possibile Possibile Possibile
Leggi impegnato Prevenuto Possibile Possibile
Lettura ripetibile Prevenuto Prevenuto Possibile
Serializzabile Prevenuto Prevenuto Prevenuto
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

La sintassi e il comportamento esatti dipendono dal database. Anche le impostazioni predefinite differiscono: PostgreSQL e SQL Server utilizzano la lettura impegnata, mentre InnoDB di MySQL utilizza la lettura ripetibile. Alcuni database forniscono garanzie più forti di quelle richieste dallo standard o trattano un livello come un altro. In PostgreSQL, ad esempio, la lettura senza commit si comporta come la lettura impegnata. Leggi sempre la documentazione del tuo database prima di fare affidamento su un comportamento specifico.

Suggerimento: Per un aggiornamento perso, apportare la modifica in una singola istruzione, come in UPDATE accounts SET balance = balance + 10. Fare il calcolo nella tua applicazione da una lettura precedente è ciò che apre il divario.

Deadlock

Un deadlock si verifica quando due transazioni detengono ciascuna un blocco di cui l’altra ha bisogno. La transazione A blocca la riga 1 e vuole la riga 2, mentre la transazione B blocca la riga 2 e vuole la riga 1. Nessuna delle due può continuare.

Database come PostgreSQL, MySQL e SQL Server lo rilevano e annullano una transazione con un errore. Questo è un comportamento normale e la tua domanda dovrebbe essere preparata per questo. Per ridurre i blocchi, aggiorna sempre le righe in un ordine coerente, ad esempio inserendo prima l’ID account più basso, mantieni le transazioni brevi e riprova quando ne viene scelto uno come vittima.

Migliori pratiche

  • Mantieni le transazioni brevi. Quelle lunghe bloccano e bloccano altri utenti.
  • Non aspettare mai un utente o un’API lenta all’interno di una transazione. Esegui questa operazione prima di iniziare o dopo.
  • Gestire sempre gli errori. Ogni percorso dovrebbe terminare con un commit o un rollback.
  • Aggiungi vincoli. Forniscono al database regole reali da applicare. Anche un buon design della tabella aiuta.
  • Utilizza buoni indici.Ricerche più veloci significano che i blocchi vengono mantenuti per meno tempo.
  • Fai attenzione ai nuovi tentativi. Riprova in caso di deadlock, ma assicurati che un’operazione non possa essere applicata due volte.
  • Testare la concorrenza di proposito. Molti di questi bug compaiono solo sotto carico, quindi i test di integrazione di base da soli potrebbero non rivelarli.

Considerazioni finali

Le transazioni trasformano diversi passaggi rischiosi in un’operazione sicura e ACID descrive le garanzie che la rendono affidabile. Ogni volta che un’azione aziendale tocca più di una riga o tabella, chiediti cosa accadrebbe se si fermasse a metà. Se la risposta ti preoccupa, inseriscila in una transazione. Per esercitarti, apri due sessioni in un database locale e prova a produrre tu stesso le anomalie.

Domande frequenti

Cos’è una transazione in SQL?

Una transazione è un gruppo di istruzioni SQL trattate come un’unità. O vengono salvati tutti con COMMIT oppure vengono annullati tutti con ROLLBACK.

Quali sono le proprietà ACID in un database?

ACID sta per atomicità, consistenza, isolamento e durabilità. Insieme, garantiscono che le transazioni siano tutto o niente, mantengano intatte le regole, non interferiscano e sopravvivano ai fallimenti.

Qual è la differenza tra COMMIT e ROLLBACK?

COMMIT salva in modo permanente tutte le modifiche apportate alla transazione. ROLLBACK li cancella e riporta i dati com’erano prima dell’inizio della transazione.

Cos’è una lettura sporca?

Una lettura sporca si verifica quando una transazione legge le modifiche che un’altra non ha ancora effettuato il commit. Se l’altra transazione viene ripristinata, i dati letti non sono mai realmente esistiti.

Quale livello di isolamento dovrei usare?

Inizia con l’impostazione predefinita del tuo database, che di solito va bene. Utilizza serializzabile per la logica critica in cui le anomalie sono inaccettabili e sii pronto a riprovare le transazioni non riuscite.

Continua a imparare

Lavora con Stack Quora

Hai bisogno di aiuto con test, WordPress o SEO?

Aiutiamo i team a fornire software migliore e a far crescere i loro siti. Raccontaci a cosa stai lavorando e ti suggeriremo chiaramente il prossimo passo.

Continua a leggere

Altre guide su test, intelligenza artificiale e sviluppo moderno

Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.

Intelligenza artificiale

Spiegazione delle allucinazioni dell'intelligenza artificiale: perché i modelli linguistici inventano le cose e come ridurle

Spiegazione delle allucinazioni dell'intelligenza artificiale: cosa sono, perché i modelli linguistici le producono, tipi comuni, come ridurle con b…

Leggi l'articolo →
DevOps

Spiegazione delle variabili d'ambiente: file .env, segreti e configurazione eseguiti correttamente

Variabili d'ambiente spiegate con esempi Python che abbiamo eseguito: lettura e impostazione, perché ogni valore è una stringa, file .env, ereditari…

Leggi l'articolo →
Sviluppo software

Spiegazione della limitazione della velocità API: algoritmi, intestazioni e gestione degli errori 429

La limitazione della velocità dell'API spiegata con una simulazione che abbiamo eseguito: bucket di token, finestra fissa, finestra scorrevole, risp…

Leggi l'articolo →
Automazione dei test

Derisione in Python: unittest.mock, patch e gli errori che fanno mentire i test

Mocking in Python con unittest.mock, testato: Mock e return_value, side_effect, patch dove viene utilizzato un nome, specifiche e autospec, date moc…

Leggi l'articolo →
Test del software

Spiegazione della copertura del codice: copertura di linea o di filiale e cosa significa realmente il 100%.

Copertura del codice spiegata con una vera esecuzione di cover.py: copertura di linea, ramo e condizione, lettura di un rapporto, perché la copertur…

Leggi l'articolo →
Database e SQL

DELETE vs TRUNCATE vs DROP in SQL: differenze, rollback e quando utilizzarli

DELETE vs TRUNCATE vs DROP spiegato con SQL testato: cosa rimuove, rollback, trigger, reimpostazione dell'identità, velocità e come differiscono Pos…

Leggi l'articolo →
Database e SQL

Spiegazione delle visualizzazioni SQL: crea, utilizza ed evita le insidie, con esempi

Viste SQL spiegate con le query che abbiamo eseguito: creazione di una vista, risultati in tempo reale, nascondere colonne, prestazioni, viste aggio…

Leggi l'articolo →
Sviluppo software

Interfaccia TypeScript e tipo: differenze reali, testate con il compilatore

Interfaccia TypeScript vs tipo, verificata con il vero compilatore: cosa possono fare entrambi, cosa può fare solo uno, fusione delle dichiarazioni,…

Leggi l'articolo →
Sviluppo software

Spiegazione di Python *args e **kwargs: funzioni flessibili con esempi chiari

Python *args e **kwargs spiegati con il codice che abbiamo eseguito: compressione e decompressione, ordine dei parametri, argomenti solo per parole …

Leggi l'articolo →
Sviluppo software

Funzioni Lambda Python: sintassi, usi reali e quando non usarli

Funzioni lambda Python spiegate con il codice che abbiamo eseguito: sintassi, ordinamento con chiave, mappa e filtro, chiusure, trap dell'associazio…

Leggi l'articolo →
Intelligenza artificiale

Cosa sono gli agenti AI? Come funzionano, con un semplice ciclo di agenti che puoi eseguire

Cosa sono gli agenti IA? Una semplice guida al ciclo dell'agente, agli strumenti, alla memoria e ai guardrail, con un piccolo ciclo Python che abbia…

Leggi l'articolo →
DevOps

Monitoraggio vs osservabilità: la vera differenza, con log, metriche e tracce

Spiegazione del monitoraggio e dell'osservabilità: errori noti e sconosciuti, log, metriche e tracce, una procedura dettagliata sugli incidenti di p…

Leggi l'articolo →
DevOps

Volumi Docker e montaggi di associazione: mantenere i dati del contenitore nel modo giusto

Volumi Docker e montaggi di collegamento spiegati: perché i dati del contenitore scompaiono, volumi denominati, montaggi di collegamento, tmpfs, ese…

Leggi l'articolo →
Automazione dei test

TDD vs BDD: differenze chiave, una caratteristica costruita in entrambi i modi e quando utilizzarli ciascuno

TDD vs BDD spiegato con una funzione di sconto costruita in entrambi i modi: refactoring rosso-verde con il codice che abbiamo eseguito, scenari "Da…

Leggi l'articolo →
Test del software

Test di accettazione da parte dell'utente (UAT): processo, lista di controllo ed esempi reali

Spiegazione del test di accettazione dell'utente: chi lo esegue, in cosa differisce dal QA, un processo in sette fasi, un modello di test case UAT, …

Leggi l'articolo →
Database e SQL

Spiegazione dei valori SQL NULL: IS NULL, COALESCE, NULLIF e le trappole da evitare

Valori SQL NULL spiegati con le query che abbiamo eseguito: logica a tre valori, IS NULL, COALESCE, NULLIF, come aggregazioni, join e ordinamento tr…

Leggi l'articolo →
Database e SQL

Istruzione SQL CASE WHEN: sintassi, esempi reali ed errori comuni

SQL CASE WHEN spiegato con le query che abbiamo eseguito: moduli semplici e cercati, ordine delle condizioni, pivot con SUM, trucchi COUNT, ordiname…

Leggi l'articolo →
Sviluppo software

Cos'è il JWT? Token Web JSON spiegati con un esempio funzionante

Cos'è il JWT? Spiegazione dei token Web JSON: le tre parti, un token creato e manomesso nel codice che abbiamo eseguito, JWT e sessioni, archiviazio…

Leggi l'articolo →
Sviluppo software

Spiegazione del loop di eventi JavaScript: stack di chiamate, microtask e timer con esempi

Il ciclo di eventi JavaScript spiegato con il codice che abbiamo eseguito: stack di chiamate, code di attività e microtask, perché setTimeout 0 non …

Leggi l'articolo →
Sviluppo software

Spiegazione dei generatori Python e del rendimento: risparmia memoria con esempi reali

Generatori Python e rendimento spiegati con il codice che abbiamo eseguito: come vengono messi in pausa e ripresi, misurato il risparmio di memoria,…

Leggi l'articolo →
Intelligenza artificiale

Cosa sono gli incorporamenti? I vettori e la somiglianza del coseno spiegati semplicemente

Cosa sono gli incorporamenti? Una guida in linguaggio semplice ai vettori, alla similarità del coseno e alla ricerca semantica, con un piccolo esemp…

Leggi l'articolo →
DevOps

Distribuzione blu-verde rispetto a quella canaria: differenze, compromessi e come scegliere

Spiegazione della distribuzione blu-verde e canary: come funziona ciascuna, costi, rischi e rollback, bucket utente stabile che abbiamo testato, mig…

Leggi l'articolo →
Automazione dei test

Test instabili: quali sono le cause e come risolverli definitivamente

Test instabili spiegati con demo che abbiamo eseguito: le cause principali, come confermarne e diagnosticarne uno, soluzioni adeguate per tempistich…

Leggi l'articolo →
Test del software

Test di carico e test di stress: differenze, metriche ed esempi k6

Spiegazione del test di carico e dello stress test: cosa dimostra ciascuno, test di picco e di assorbimento, le metriche che contano, perché le medi…

Leggi l'articolo →
Test del software

Caso di test e scenario di test: differenze chiave, esempi e quando utilizzarli

Spiegazione del caso di test e dello scenario di test: definizioni chiare, una tabella affiancata, una funzione di reimpostazione della password pre…

Leggi l'articolo →
Database e SQL

Ottimizzazione delle query SQL: leggi i piani di esecuzione e correggi query lente, con tempistiche

Ottimizzazione delle query SQL testata su un milione di righe: leggi i piani di esecuzione, aggiungi gli indici corretti, correggi filtri non aggior…

Leggi l'articolo →
Database e SQL

SQL UNION vs UNION ALL: differenze, esempi e prestazioni testate

SQL UNION vs UNION ALL spiegati con le query che abbiamo eseguito: duplicati, regole seguite da entrambi, un vero bug di dati, prestazioni misurate,…

Leggi l'articolo →
Sviluppo software

Tutorial sull'API di recupero JavaScript: GET, POST, gestione degli errori e timeout

Un tutorial sull'API JavaScript Fetch testato su un server locale: GET e POST, perché 404 non genera eccezioni, un helper riutilizzabile, stringhe d…

Leggi l'articolo →
Sviluppo software

Gestione dei file Python: lettura, scrittura, CSV, JSON e pathlib con esempi

Gestione dei file Python spiegata con il codice che abbiamo eseguito: modalità aperte, con, lettura di file di grandi dimensioni, CSV, JSON, pathlib…

Leggi l'articolo →
Sviluppo software

Classi e oggetti Python: tutorial OOP con esempi reali

Classi e oggetti Python spiegati con il codice che abbiamo eseguito: __init__, metodi, attributi di classe e istanza, ereditarietà, proprietà, metod…

Leggi l'articolo →
Intelligenza artificiale

Che cos'è un modello linguistico di grandi dimensioni? Come funzionano i LLM, spiegato senza esagerazioni

Cos’è un modello linguistico ampio? LLM spiegati in un linguaggio semplice: token, incorporamenti, attenzione, formazione, finestre di temperatura e…

Leggi l'articolo →
DevOps

Comandi Linux per principianti: la guida essenziale del terminale con esempi

Comandi Linux per principianti, raggruppati per attività: navigazione, file, visualizzazione log, grep, pipe, permessi, processi e archivi, con un e…

Leggi l'articolo →
Automazione dei test

Selenio vs drammaturgo: differenze chiave, codice a confronto e quale scegliere

Selenium vs Playwright a confronto: architettura, attesa, supporto per browser e linguaggio, debug, lo stesso test in entrambi gli strumenti, consig…

Leggi l'articolo →
Test del software

Partizionamento di equivalenza: tecnica di progettazione dei test spiegata con esempi pratici

Spiegazione del partizionamento di equivalenza: come trovare partizioni valide e non valide, esempi funzionanti per età, password e coupon, test che…

Leggi l'articolo →
Test del software

Gravità vs priorità nel test del software: differenze, matrice ed esempi reali

Spiegazione della gravità e della priorità nei test del software: definizioni chiare, una matrice a quattro vie con esempi, scale di livello, chi im…

Leggi l'articolo →
Database e SQL

Esercitazione sulle sottoquery SQL: tipi, sottoquery correlate ed EXISTS con esempi

Un tutorial sulle sottoquery SQL con le query che abbiamo eseguito: sottoquery scalari, IN, FROM e SELECT, sottoquery correlate, EXISTS, trap NOT IN…

Leggi l'articolo →
Database e SQL

Spiegazione di transazioni SQL e ACID: COMMIT, ROLLBACK e livelli di isolamento

Transazioni SQL e ACID spiegate con un bonifico bancario eseguito: COMMIT, ROLLBACK, punti di salvataggio, blocchi, livelli di isolamento, letture s…

Leggi l'articolo →
Sviluppo software

Git merge vs rebase: differenze, esempi e quando usare ciascuno

Git merge vs rebase spiegato con output reale del log, una tabella di confronto, la regola d'oro del rebase e un flusso di lavoro sicuro per i team.

Leggi l'articolo →
Sviluppo software

List comprehension in Python: sintassi, esempi e quando evitarla

List comprehension in Python spiegata: sintassi, filtri, if-else, cicli annidati, tempi misurati e i casi in cui un normale ciclo for è meglio.

Leggi l'articolo →
Database e SQL

SQL JOIN spiegati con esempi (Inner, Left, Right, Full)

Capisci i JOIN SQL passo dopo passo con tabelle e query di esempio: INNER, LEFT, RIGHT, FULL, CROSS e SELF, con errori comuni e consigli sulle prest…

Leggi l'articolo →