Menu

SAVEPOINT in SQLite: transazioni annidate con ROLLBACK TO

Come funzionano i savepoint in SQLite: segnaposto con nome dentro una transazione a cui puoi tornare indietro senza buttare via tutto.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Un savepoint è un segnalibro con nome dentro una transazione

Una transazione normale è tutto o niente: tutto ciò che sta tra BEGIN e COMMIT viene salvato insieme oppure scartato insieme. Di solito è quello che vuoi, ma a volte ti serve una granularità più fine. "Prova questo gruppo di modifiche; se va storto, annulla solo quel gruppo e tieni vivo il resto della transazione."

È questo un savepoint. Lasci un segnalibro con nome, fai del lavoro e poi tieni il lavoro (RELEASE) oppure torni indietro al segnalibro (ROLLBACK TO).

L'addebito di Ada e l'accredito di Boris restano entrambi. L'aggiornamento sbagliato su Nobody è stato annullato senza perdere il resto della transazione.

I tre comandi

Tre istruzioni sono tutta l'API:

  • SAVEPOINT name: imposta un segnalibro.
  • RELEASE SAVEPOINT name: tiene il lavoro fatto dal segnalibro in poi e rimuove il segnalibro.
  • ROLLBACK TO SAVEPOINT name: annulla tutto ciò che è stato fatto dal segnalibro in poi; il segnalibro resta al suo posto, così puoi riprovare.

La parola SAVEPOINT dopo RELEASE e ROLLBACK TO è facoltativa: funzionano sia RELEASE risky sia ROLLBACK TO risky.

Per il database finale, la riga tentativo passo 2 non è mai esistita. Tutto il resto viene salvato.

Savepoint senza una transazione esterna

Ecco una piccola sorpresa: puoi usare SAVEPOINT senza un BEGIN prima. SQLite apre una transazione per te senza dirlo, e il savepoint più esterno fa la parte della transazione stessa. RELEASE su quel savepoint fa il commit, ROLLBACK TO torna indietro senza fare il commit.

Ecco perché a volte i savepoint vengono descritti come "transazioni con nome". Ma mescolare i due stili nel codice reale crea confusione: scegline uno. La maggior parte delle persone usa BEGIN ... COMMIT esplicito per il confine esterno e i savepoint solo per i punti interni di annullamento parziale.

Savepoint annidati

I savepoint si impilano. Puoi impostarne uno dentro un altro e annullare quello interno senza toccare quello esterno:

Contenuto finale: a, b, d. Tornare a inner ha rimosso c ma ha lasciato intatto il lavoro fatto prima di inner (l'insert di b), e la transazione è andata avanti.

Tornare a un savepoint esterno scarta anche tutto ciò che è stato fatto ai livelli interni: l'intera pila sopra quel nome si srotola in un colpo:

Sia b sia c sono spariti. ROLLBACK TO outer annulla tutto da quando è stato impostato outer, compresi inner e l'insert di c.

Perché usare i savepoint?

Il caso classico è l'elaborazione di un lotto in cui i singoli elementi possono fallire senza buttare via tutto il lotto. Racchiudi ogni elemento in un savepoint; se fallisce, torna al savepoint e prosegui:

Nel codice di un'applicazione reale, l'insert sbagliato solleva un errore e l'applicazione lo intercetta, esegue ROLLBACK TO e continua. Due righe buone vengono salvate; quella sbagliata non avvelena il lotto.

È anche così che ORM e strumenti di migrazione implementano le transazioni annidate: non annidano davvero i blocchi BEGIN (SQLite non lo permette), ma trasformano le chiamate annidate in savepoint.

Alcune cose a cui fare attenzione

Qualche dettaglio che frega chi usa i savepoint per la prima volta:

  • COMMIT fa sempre il commit dell'intera transazione. Non importa quanti savepoint aperti hai: COMMIT (o il suo alias END) chiude tutta la transazione esterna. Non pensare a RELEASE come a un commit parziale; niente è durevole finché la transazione che lo contiene non fa il commit.
  • ROLLBACK (senza TO) annulla tutto. Chiude la transazione e scarta tutti i savepoint aperti. Usa ROLLBACK TO name quando vuoi tenere viva la transazione.
  • Un savepoint resta aperto finché non viene rilasciato o superato da un rollback. Dimenticare RELEASE non fa perdere dati, ma il segnalibro resta lì finché la transazione non finisce.
  • I nomi non devono essere unici. Se imposti SAVEPOINT s due volte, ROLLBACK TO s trova il più recente. Utile per la ricorsione; fonte di confusione se capita per sbaglio.

Prossimo passo: le viste

I savepoint ti danno un controllo più fine sulle scritture. Il passo successivo è dare forma alle letture: salvare una query come oggetto riutilizzabile con un nome, da cui fare SELECT come da una tabella. È una vista, ed è il prossimo argomento.

Domande frequenti

Cos'è un savepoint in SQLite?

Un savepoint è un segnaposto con nome che imposti dentro una transazione. In seguito puoi fare ROLLBACK TO su quel nome per annullare tutto ciò che è stato fatto dopo, oppure RELEASE per tenere le modifiche ed eliminare il segnaposto. I savepoint ti permettono di trattare parti di una transazione come unità più piccole e recuperabili.

Che differenza c'è tra un savepoint e una transazione in SQLite?

Una transazione inizia con BEGIN e finisce con COMMIT o ROLLBACK. Un savepoint si imposta dentro una transazione con SAVEPOINT name e ti dà un punto di annullamento parziale. Tornare a un savepoint non chiude la transazione che lo contiene: puoi continuare a lavorare e fare il commit più tardi.

I savepoint di SQLite possono essere annidati?

Sì. Puoi impilare savepoint con nomi diversi, e ROLLBACK TO outer annulla tutto fino a quel livello, compresi i savepoint interni. I nomi non devono essere unici: SQLite usa il savepoint più recente con quel nome, il classico comportamento a pila.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA