Una transazione in SQL è un'unità di esecuzione che raggruppa una o più attività insieme. Una transazione è considerata riuscita se tutte le attività al suo interno vengono eseguite senza errori.
Tuttavia, se una qualsiasi delle attività all'interno di una transazione non viene eseguita, l'intera transazione fallisce. Una transazione ha solo due risultati:riuscita o non riuscita.
Uno scenario pratico
Considera un esempio pratico di bancomat (Automated Teller Machine). Vai al bancomat e ti chiede la carta. Esegue una query per verificare se la carta è valida o meno. Successivamente, ti chiede il codice PIN. Ancora una volta esegue una query per abbinare il codice pin. L'ATM ti chiede quindi l'importo che desideri prelevare e tu inserisci l'importo che desideri. L'ATM esegue un'altra query per detrarre tale importo dal tuo account e quindi eroga i fondi a te.
Cosa succede se l'importo viene detratto dal tuo account e quindi il sistema si arresta in modo anomalo a causa di un'interruzione di corrente senza erogare le banconote?
Questo è problematico perché il cliente ha i fondi dedotti senza aver ricevuto denaro. È qui che le transazioni possono essere utili.
In caso di arresto anomalo del sistema o di qualsiasi altro errore, tutte le attività all'interno della transazione vengono annullate. Pertanto, nel caso di un bancomat, l'importo verrà riaccreditato sul tuo conto se per qualsiasi motivo non sei in grado di prelevarlo.
Che cos'è una transazione?
Nella sua forma più semplice, una modifica in una tabella di database è una transazione. Pertanto, le istruzioni INSERT, UPDATE e DELETE sono tutte istruzioni di transazione. Quando si scrive una query, viene eseguita una transazione. Tuttavia, questa transazione non può essere annullata. Di seguito vedremo come vengono create, impegnate e ripristinate le transazioni, ma prima creiamo alcuni dati fittizi con cui lavorare.
Preparazione dei dati
Esegui il seguente script sul tuo server di database.
CREATE DATABASE schooldb CREATE TABLE student ( id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, gender VARCHAR(50) NOT NULL, age INT NOT NULL, total_score INT NOT NULL, ) INSERT INTO student VALUES (1, 'Jolly', 'Female', 20, 500), (2, 'Jon', 'Male', 22, 545), (3, 'Sara', 'Female', 25, 600), (4, 'Laura', 'Female', 18, 400), (5, 'Alan', 'Male', 20, 500)
Lo script SQL di cui sopra crea un database schooldb. In questo database, viene creato uno studente tabella e alcuni dati fittizi vengono aggiunti a quella tabella.
Esecuzione di query senza transazioni
Eseguiamo tre query standard. Non stiamo usando le transazioni al momento.
INSERT INTO student VALUES (6, 'Suzi', 'Female', 25, 395) UPDATE student SET age = 'Six' WHERE id= 6 DELETE from student WHERE id = 6
Qui la prima query inserisce un record studente nel database. La seconda query aggiorna l'età dello studente e la terza query elimina il record appena inserito.
Se esegui lo script precedente, vedrai che il record verrà inserito nel database e quindi si verificherà un errore durante l'esecuzione della seconda query.
Se osservi la seconda query, stiamo aggiornando age memorizzando un valore stringa nella colonna age che può memorizzare dati di tipo intero. Pertanto verrà generato un errore. Tuttavia, la prima query verrà comunque completata correttamente. Ciò significa che se selezioni tutti i record dalla tabella degli studenti, vedrai il record appena inserito.
[id tabella=23 /]
Puoi vedere che il record con id=6 e nome 'Suzi' è stato inserito nel database. Ma non è stato possibile aggiornare l'età e la seconda query non è riuscita.
E se non lo vogliamo? Cosa succede se vogliamo essere sicuri che tutte le query vengano eseguite correttamente o nessuna delle query venga eseguita affatto? È qui che le transazioni tornano utili.
Esecuzione di query con transazioni
Ora eseguiamo le tre query sopra all'interno di una transazione.
Per prima cosa, vediamo come creare e confermare una transazione.
Creazione di una transazione
Per eseguire una o più query come transazione, è sufficiente racchiudere le query all'interno delle parole chiave BEGIN TRANSACTION e COMMIT TRANSACTION. BEGIN TRANSACTION dichiara l'inizio di una TRANSACTION mentre COMMIT TRANSACTION indica che la transazione è stata completata.
Eseguiamo tre nuove query sul database che abbiamo creato in precedenza come transazione. Aggiungeremo un nuovo record per un nuovo studente con ID 7.
BEGIN TRANSACTION INSERT INTO student VALUES (7, 'Jena', 'Female', 22, 456) UPDATE student SET age = 'Twenty Three' WHERE id= 7 DELETE from student WHERE id = 7 COMMIT TRANSACTION
Quando viene eseguita la transazione precedente, si verificherà nuovamente un errore nella seconda query poiché di nuovo un valore di tipo stringa viene memorizzato nella colonna età che memorizza solo dati di tipo intero.
Tuttavia, poiché l'errore si verifica all'interno di una transazione, tutte le query eseguite correttamente prima che si verificasse questo errore verranno automaticamente ripristinate. Pertanto, verrà eseguito il rollback anche della prima query che inserisce un nuovo record studente con id =7 e nome "Jena".
Ora, se selezioni tutti i record dalla tabella degli studenti, vedrai che il nuovo record per 'Jena' non è stato inserito.
Ripristino manuale delle transazioni
Sappiamo che se una query genera un errore all'interno di una transazione, l'intera transazione, comprese tutte le query già eseguite, viene automaticamente annullata. Tuttavia, possiamo anche ripristinare manualmente una transazione manualmente ogni volta che lo desideriamo.
Per annullare una transazione viene utilizzata la parola chiave ROLLBACK seguita dal nome della transazione. Per denominare una transazione, viene utilizzata la seguente sintassi:
BEGIN TRANSACTION Transaction_name
Supponiamo di volere che la nostra tabella studenti non contenga record contenenti nomi di studenti duplicati. Aggiungeremo un record per un nuovo studente. Verificheremo quindi se nel database esiste uno studente con un nome identico al nome dello studente appena inserito. Se lo studente con quel nome non esiste già, impegneremo la nostra transazione. Se esiste uno studente con quel nome, eseguiremo il rollback della nostra transazione. Utilizzeremo le istruzioni condizionali nella nostra query.
Dai un'occhiata alla seguente transazione:
DECLARE @NameCount int BEGIN TRANSACTION AddStudent INSERT INTO student VALUES (8, 'Jacob', 'Male', 21, 600) SELECT @NameCount = COUNT(*) FROM student WHERE name = 'Jacob' IF @NameCount > 1 BEGIN ROLLBACK TRANSACTION AddStudent PRINT 'A student with this name already exists' END ELSE BEGIN COMMIT TRANSACTION AddStudent PRINT 'New record added successfully' END
Guarda attentamente lo script sopra. Qui stanno accadendo molte cose.
Nella prima riga, creiamo una variabile SQL di tipo intero NameCount.
In seguito, iniziamo una transazione denominata "AddStudent". Puoi dare qualsiasi nome alla tua transazione.
All'interno della transazione, abbiamo inserito un nuovo record per uno studente con id =8 e nome 'Jacob'.
In seguito, utilizzando la funzione di aggregazione COUNT, contiamo il numero di record degli studenti in cui il nome è "Jacob" e memorizziamo il risultato nella variabile "NameCount".
Se il valore della variabile è maggiore di 1, significa che uno studente con il nome 'Jacob' esiste già nel database. In tal caso, eseguiamo il ROLLBACK della nostra transazione e STAMPIAMO un messaggio sullo schermo che dice "Esiste già uno studente con questo nome".
In caso contrario, impegniamo la nostra transazione e visualizziamo il messaggio "Nuovo record aggiunto con successo".
Quando esegui la transazione di cui sopra per la prima volta, non ci sarà un record studente con il nome "Jacob". Pertanto la transazione verrà confermata e verrà stampato il seguente messaggio:
Ora prova a eseguire il seguente script SQL sul server:
DECLARE @NameCount int BEGIN TRANSACTION AddStudent INSERT INTO student VALUES (9, 'Jacob', 'Male', 22, 400) SELECT @NameCount = COUNT(*) FROM student WHERE name = 'Jacob' IF @NameCount > 1 BEGIN ROLLBACK TRANSACTION AddStudent PRINT 'A student with this name already exists' END ELSE BEGIN COMMIT TRANSACTION PRINT 'New record added successfully' END
Anche in questo caso, stiamo inserendo il record dello studente con id =9 e nome "Jacob". Poiché nel database esiste già un record studente con il nome "Jacob", la transazione verrà annullata e verrà stampato il seguente messaggio:
Link utili
- Classi sulle transazioni SQL