04. Transazioni

Il concetto di transazione

Nella teoria delle basi di dati, una transazione è una sequenza di operazioni che, se eseguite tutte in modo corretto, produce un aggiornamento della base di dati. Qualora vi sia insuccesso anche in una sola delle operazioni, la transazione deve fallire e la base dati deve essere ripristinata al valore iniziale (cioè allo stato antecedente all'inizio della transazione).

In letteratura si dice che le transazioni devono possedere le seguenti proprietà logiche:

    • Atomicità (l'insieme delle operazioni deve essere indivisibile);

    • Consistenza (i dati registrati devono essere coerenti);

    • Isolamento (le operazioni eseguite in una transazione non devono interferire con altre transazioni in esecuzione contemporaneamente);

    • Durabilità (una volta applicati gli aggiornamenti essi devono essere permanenti).

Tali proprietà sono indicate con l'acronimo ACID.


Transazioni in SQLite

In SQLite in corrispondenza dei comandi di inserimento, aggiornamento e cancellazione parte implicitamente una transazione, costituita dalla singola operazione.

E' possibile estendere il concetto di transazione definendo manualmente l'inizio della transazione con il comando

BEGIN TRANSACTION;

e la fine della transazione con uno dei comandi

COMMIT;

ROLLBACK;

Il comando COMMIT determina la registrazione dei dati sul database in modo effettivo e permanente mentre il comando ROLLBACK determina il ripristino della base dati allo stato precedente.

Se si interfaccia SQLite da Python, le transazioni sono definite in modo implicito pertanto non occorre utilizzare il comando BEGIN TRANSACTION per delimitare l'inizio della transazione mentre è obbligatorio richiamare il comando di COMMIT per rendere permanenti le modifiche.

Esempio:

Dopo aver avviato la shell di SQLite, eseguiamo uno ad uno i seguenti comandi SQL

BEGIN TRANSACTION;

CREATE TABLE Test(Id INTEGER NOT NULL);

INSERT INTO Test VALUES(1);

INSERT INTO Test VALUES(2);

INSERT INTO Test VALUES(3);

INSERT INTO Test VALUES(NULL);

Poiché la tabella Test è stata creata prescrivendo che non siano ammessi valori NULL, l'ultimo comando di INSERT fallirà.

A questo punto potremo decidere di rendere permanenti le modifiche apportate al database con il comando

COMMIT;

oppure di annullare tutte le modifiche e tornare allo stato iniziale con il comando

ROLLBACK;

Per prima cosa annulliamo le operazioni con il comando ROLLBACK; e verifichiamo se la tabella Test è presente nel database eseguendo il comando evidenziato il grassetto

sqlite>.schema

Ci aspettiamo che il comando non mostri alcuna informazione.

Ripetiamo nuovamente tutti i comandi della transazione chiudendo questa volta la transazione con il comando COMMIT;

BEGIN TRANSACTION;

CREATE TABLE Test(Id INTEGER NOT NULL);

INSERT INTO Test VALUES(1);

INSERT INTO Test VALUES(2);

INSERT INTO Test VALUES(3);

INSERT INTO Test VALUES(NULL);

COMMIT;

Accertiamoci che le registrazioni siano avvenute correttamente eseguendo nuovamente il comando evidenziato in grassetto

sqlite>.schema

Questa volta ci aspettiamo che sia mostrata la definizione della tabella Test.

Possiamo completare la verifica eseguendo una interrogazione sulla tabella con il comando

SELECT * FROM Test;

e accertandoci che siano presenti i record con valori 1, 2, e 3.