Transaktsioonid on tegevused, kus kõik tegevused kas õnnestuvad edukalt või ei õnnestu üldse. SQL Server tunnistab kahte tüüpi transaktsioone:
- Automaatsed transaktsioonid – Server tekitab need ise kõigi muutmistegevustega st UPDATE, INSERT ja DELETE lausetega. Sisuliselt tähendab see seda, et kui nt üritate muuta 10 kirje väärtust ja ühe kirje väärtuse muutmine ei õnnestu, siis ei muudeta neist ühtegi.
- Käsitsi tehtud transaktsioonid – Programmeerija loodud tegevuste jadad, mis peavad kõik õnnestuma.
Transaktsiooni tekitamiseks on käsk BEGIN TRAN. Selle järele tulevad kõik soovitud tegevused. Kui transaktsioon lõpeb edukalt, siis saab selle lõpetada käsuga COMMIT TRAN. Kui midagi läheb valesti, saab selle tagasi kerida käsuga ROLLBACK TRAN.
Vaatame näiteks, kuidas võiks luua protseduuri pangaülekandeks. Kuna SQL Server 2005 tunnistab uut TRY CATCH konstruktsiooni vigade haldamiseks, siis vaatleme seda näidet nii SQL Server 2000 kui ka SQL Server 2005 baasil.
CREATE PROC ylekanne2
@kellelt int,
@kellele int,
@summa money
AS
BEGIN TRAN
BEGIN TRY
UPDATE konto
SET jaak = jaak - @summa
WHERE omanik = @kellelt
UPDATE konto
SET jaak = jaak + @summa
WHERE omanik = @kellele
END TRY
BEGIN CATCH
IF @@trancount > 0
ROLLBACK TRAN
END CATCH
IF @@TRANCOUNT > 0
COMMIT TRANSACTION;
Samast raha ülekandmisest nüüd pikem näide. Pigem jäägu ülekanne teostamata, kui et toimingu sees osa raha ära kaob või juurde tekib. Et kontodega toimetada, sai loodud võimalikult lihtne tabel – vaid konto number ning seal olev saldo.
create table kontod(
id int identity not null primary key,
saldo money
)
Edasi luuakse salvestatud protseduur raha ülekandeks. Kust kontolt võtta, kuhu panna ning kui suur on summa. Esimesed kaks arvu tähendavad siis vastavate kontode numbreid.
create procedure ylekanne
(@kust int, @kuhu int, @summa money)
as
Abimuutujas hoitakse meeles, kas kõik õnnestus hästi.
declare @korras as int
Esialgu probleeme pole, nii et @korras saab väärtuseks 1.
set @korras=1
Kogu järgnev toiming pannakse transaktsiooni sisse. See tähendab, et sealsed muutused kas toimivad tervikuna või jäävad sootuks ära.
begin transaction
Kõigepealt kontrollitakse, kas esimeselt kontolt on võimalik vastav summa maha võtta. Kui saab, siis võetakse, muul juhul väljastatakse veateade ja muutujasse @korras antakse teada, et kord läks kaduma.
if (select saldo from kontod where id=@kust)>=@summa begin
update kontod set saldo=saldo-@summa where id=@kust
end else begin
set @korras=0
raiserror('raha otsas', 1, 1)
end
Järgmise sammuga kontrollitakse, et ka see konto ikka olemas on, kuhu raha kanda soovitakse. Hariliku UPDATE-lause puhul ei antaks isegi veateadet juhul, kui saajakontot olemas poleks. Siinse kontrolliga aga tehakse olemasolu kindlaks ja vaid sel juhul suurendatakse sealset summat. Muul juhul jäetakse jälle meelde, et asjad pole korras.
if exists(select saldo from kontod where id=@kuhu) begin
update kontod set saldo=saldo+@summa where id=@kuhu
end else begin
set @korras=0
end
Edasi jääb üle vaid muutuja järgi otsustada, kas toiming kinnitada või tagasi lükata.
if @korras=1
commit transaction
else begin
rollback transaction
print 'probleem'
end
Ja et protseduuri käivitamise tulemusena oleks ka kontode operatsioonijärgset seisu näha, selleks lõppu üks SELECT-lause.
select * from kontod where id in (@kust, @kuhu)
Ning kood tervikuna.
create procedure ylekanne
(@kust int, @kuhu int, @summa money)
as
declare @korras as int
set @korras=1
begin transaction
if (select saldo from kontod where id=@kust)>=@summa begin
update kontod set saldo=saldo-@summa where id=@kust
end else begin
set @korras=0
raiserror('raha otsas', 1, 1)
end
if exists(select saldo from kontod where id=@kuhu) begin
update kontod set saldo=saldo+@summa where id=@kuhu
end else begin
set @korras=0
end
if @korras=1
commit transaction
else begin
rollback transaction
print 'probleem'
end
select * from kontod where id in (@kust, @kuhu)
Tahtes loodud protseduur käivitada, tuleb siis ette anda andjakonto, saajakonto ja ülekantav summa. Ning juhul, kui ülekanne on võimalik, see ka tehakse.
EXEC ylekanne 1, 4, 100