En transaktion i SQL är en enhet för exekvering som grupperar en eller flera uppgifter. En transaktion anses vara framgångsrik om alla uppgifter inom den utförs utan fel.
Men om någon av uppgifterna i en transaktion misslyckas, misslyckas hela transaktionen. En transaktion har bara två resultat:framgångsrik eller misslyckad.
Ett praktiskt scenario
Tänk på ett praktiskt exempel på en bankomat (Automated Teller Machine). Du går till bankomaten och den frågar efter ditt kort. Den kör en fråga för att kontrollera om kortet är giltigt eller inte. Därefter ber den dig om din pinkod. Återigen kör den en fråga för att matcha pinkoden. Bankomaten frågar dig sedan om det belopp du vill ta ut och du anger det belopp du vill ha. Bankomaten utför en annan fråga för att dra av det beloppet från ditt konto och skickar sedan ut pengarna till dig.
Vad händer om beloppet dras från ditt konto och sedan systemet kraschar på grund av ett strömavbrott utan att sedlarna lämnas ut?
Detta är problematiskt eftersom kunden får pengarna dragna utan att ha fått några pengar. Det är här transaktioner kan vara praktiska.
I händelse av en systemkrasch eller något annat fel, återställs alla uppgifter i transaktionen. Därför, i fallet med en bankomat, kommer beloppet att läggas tillbaka till ditt konto om du inte kan ta ut det av någon anledning.
Vad är en transaktion?
I sin enklaste är en ändring i en databastabell en transaktion. Därför är INSERT-, UPDATE- och DELETE-satser alla transaktionssatser. När du skriver en fråga utförs en transaktion. Denna transaktion kan dock inte ångras. Vi kommer att se hur transaktioner skapas, genomförs och rullas tillbaka nedan, men låt oss först skapa lite dummydata att arbeta med.
Förbereda data
Kör följande skript på din databasserver.
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)
Ovanstående SQL-skript skapar en databas schooldb. I denna databas skapas en tabellstudent och en del dummydata läggs till i den tabellen.
Köra frågor utan transaktioner
Låt oss köra tre standardfrågor. Vi använder inte transaktioner för tillfället.
INSERT INTO student VALUES (6, 'Suzi', 'Female', 25, 395) UPDATE student SET age = 'Six' WHERE id= 6 DELETE from student WHERE id = 6
Här infogar den första frågan en studentpost i databasen. Den andra frågan uppdaterar elevens ålder och den tredje frågan tar bort den nyligen infogade posten.
Om du kör ovanstående skript kommer du att se att posten kommer att infogas i databasen och då kommer ett fel att uppstå när den andra frågan körs.
Om du tittar på den andra frågan uppdaterar vi ålder genom att lagra ett strängvärde i ålderskolumnen som kan lagra heltalstypsdata. Därför kommer ett fel att kastas. Den första frågan kommer dock fortfarande att slutföras framgångsrikt. Det betyder att om du väljer alla poster från elevtabellen kommer du att se nyinfogad post.
[tabell-id=23 /]
Du kan se att posten med id=6 och namnet 'Suzi' har infogats i databasen. Men åldern kunde inte uppdateras och den andra frågan misslyckades.
Vad händer om vi inte vill ha det här? Vad händer om vi vill vara säkra på att antingen alla frågor körs framgångsrikt eller att ingen av frågorna körs alls? Det är här transaktioner kommer till användning.
Köra frågor med transaktioner
Låt oss nu utföra de tre frågorna ovan inom en transaktion.
Låt oss först se hur man skapar och genomför en transaktion.
Skapa en transaktion
För att köra en fråga/frågor som en transaktion linda frågorna inom nyckelorden BEGIN TRANSACTION och COMMIT TRANSACTION. BEGIN TRANSACTION förklarar starten av en TRANSACTION medan COMMIT TRANSACTION anger att transaktionen har slutförts.
Låt oss köra tre nya frågor på databasen vi skapade tidigare som en transaktion. Vi kommer att lägga till ett nytt rekord för en ny student med 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
När transaktionen ovan exekveras, kommer återigen ett fel att uppstå i den andra frågan eftersom återigen ett strängtypvärde lagras i ålderskolumnen som endast lagrar heltalstypdata.
Men eftersom felet uppstår i en transaktion kommer alla frågor som kördes framgångsrikt innan detta fel inträffade automatiskt att återställas. Därför kommer den första frågan som infogar ett nytt studentrekord med id =7 och namnet "Jena" också att återställas.
Nu, om du väljer alla poster från elevtabellen, kommer du att se att den nya posten för "Jena" inte har infogats.
Manuell återställning av transaktioner
Vi vet att om en fråga ger ett fel i en transaktion, återställs hela transaktionen, inklusive alla redan utförda frågor, automatiskt. Men vi kan också manuellt återställa en transaktion manuellt när vi vill.
För att återställa en transaktion används nyckelordet ROLLBACK följt av namnet på transaktionen. För att namnge en transaktion används följande syntax:
BEGIN TRANSACTION Transaction_name
Anta att vi vill att vår elevtabell inte ska ha några poster som innehåller dubbletter av elevnamn. Vi kommer att lägga till ett rekord för en ny elev. Vi kommer då att kontrollera om det finns en elev med ett namn som är identiskt med namnet på den nyligen infogade eleven i databasen. Om studenten med det namnet inte redan finns kommer vi att genomföra vår transaktion. Om det finns en student med det namnet återställer vi vår transaktion. Vi kommer att använda villkorliga uttalanden i vår förfrågan.
Ta en titt på följande transaktion:
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
Ta en noggrann titt på skriptet ovan. Det händer mycket här.
På den första raden skapar vi en heltalstyp SQL-variabel NameCount.
Närnäst påbörjar vi en transaktion som heter 'AddStudent'. Du kan ge vilket namn som helst på din transaktion.
Inuti transaktionen infogade vi ett nytt rekord för en elev med id =8 och namnet "Jacob".
Närnäst, med hjälp av COUNT aggregationsfunktionen räknar vi antalet elevposter där namnet är 'Jacob' och lagrar resultatet i variabeln 'NameCount'.
Om värdet på variabeln är större än 1 betyder det att en elev med namnet 'Jacob' redan finns i databasen. I så fall ROLLBACKAR vi vår transaktion och SKRIVER ut ett meddelande på skärmen att "En student med detta namn finns redan".
Om inte, genomför vi vår transaktion och visar meddelandet "Ny post har lagts till framgångsrikt".
När du kör transaktionen ovan för första gången kommer det inte att finnas en studentpost med namnet "Jacob". Därför kommer transaktionen att genomföras och följande meddelande kommer att skrivas ut:
Försök nu att köra följande SQL-skript på servern:
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
Även här infogar vi studentpost med id =9 och namnet "Jacob". Eftersom en studentpost med namnet "Jacob" redan finns i databasen, kommer transaktionen att rullas tillbaka och följande meddelande kommer att skrivas ut:
Användbara länkar
- Klasser om SQL-transaktioner