Alef, moos ja transaktsioonid

16.02.2008  |  Gunnar

Kord mõtlesid ühed targad inimesed välja sellise asja nagu database transaction ning leidsid, et see on üks igati väärt asi. Pagana palju jääb igasugust peavalu  vähemaks nii arendajatel, adminidel kui ka lõppkasutajatel. Ometi sünnitab tänapäev visa järjepidevusega juurde järjest uusi arendajaid, kelle jaoks on transaktsioonid sama selged teemad kui kuu tagumine külg. Uurime siis andmebaasi transaktsioone pisut ja muudame oma süsteemid senisest paremaks.

Mis on transaktsioon?

Transaktsioon on defineeritud kui tegevuste kogum, mida käsitletakse ühtse tegevusena. See tähendab seda, et transaktsioon loetakse õnnestunuks kui õnnestuvad kõik tegevused, mis selle alla kuuluvad. Transaktsioon loetakse ebaõnnestunuks kui ebaõnnestub vähemalt üks selle alla kuuluv tegevus. Enne kui edasi läheme, vaatame korra reaalelulist näidet.

Näiteks Kreisi Raadiost tuntud käsk "Alef, pane moosipurk kapi peale" on ka käsitletav transaktsioonina, sest tegevus nimega "moosipurgi kapi peale panemine" moodustab tegevuste kogumi. Kogumisse kuuluvad sellised tegevused:

  1. Alef tõuseb püsti,
  2. Alef tõstab tabureti kapi juurde,
  3. Alef võtab laualt moosipurgi,
  4. Alef ronib tabureti peale,
  5. Alef paneb moosipurgi kapi peale.

Kui üks neist tegevustest ebaõnnestub, siis ebaõnnestub terve antud transaktsioon. Näiteks võib Alef püsti tõusmisel väänata välja jala, taburetil võib tõstmisel hakata jalg logisema, Alef võib moosipurgi maha pillata jne. Võimalusi erinevateks ebaõnnestumisteks igal sammul on mitmeid. Kui üks neist alamtegevustest ebaõnnestub, ebaõnnestub kogu tegevus, millel nimeks "Alef, pane moosipurk kapi peale".

Reaaleluline näide andmebaasi transaktsioonidest

Üks reaaleluline näide on näiteks täidetud küsitlusankeedi salvestamine andmebaasi. Vastused salvestatakse vastamiste tabelisse, kus viiakse kokku vajastaja ja vastused. Lähenemine garanteerib selle, et säilub kolmas normaalkuju ning seega samu andmeid ei dubleerita.

Lihtsamal juhul on igal küsimusel ainult üks võimalik vastus ning seega tekib vastamiste tabelisse iga kasutaja kohta antud ankeedi kohta sama palju ridu kui on ankeedis küsimusi. Kõik antud kasutaja vastused peame salvestama ühe korraga, sest muidu moonutame reaalsust - kasutaja ei täitnud ankeeti osaliselt, vaid vastas kõikidele küsimustele. Kui salvestamine ebaõnnestub, siis täidab kasutaja ankeedi uuesti ja püüab jälle salvestada.

Nüüd tulevadki mängu transaktsioonid. Me defineerime ankeedi salvestamise kui ühe tööühiku, mille alla kuulub mitu tegevust. Antud juhul on siis tegevusteks vastuste salvestamised vastuste tabelisse. Kui kasvõi ühe vastuse salvestamine ebaõnnestub, loeme terve täidetud ankeedi salvestamise ebaõnnestunuks.

BEGIN TRANSACTION

-- Neid sisestuskäske tekitab rakendus nii palju, kui on ankeedis küsimusi.
-- answer_id on märgitud parameetriga, sest see väärtus on igakord erinev.

INSERT INTO user_answers (USER_ID, answer_id) VALUES (1, @answer_id)

COMMIT

Kui käsu "Alef, pane kõik moospurgid kapi peale" täitmisel pillab Alef ühe purgi põrandale katki, pole see käsk siiski täidetud. Kui Alef teatab isale, et kõik purgid on nüüd kapi peal, vastab morn isa midagi sellist: "Aga ühe pillasid sa ju maha!"

Transaktsioonide alustamine ja lõpetamine

Et transaktsiooni sisse kuulub mitu tegevust ning andmebaasiserveril pole ilma meie abita õrna aimugi, millal transaktsiooniga kas alustada või lõpetada, siis peame me ise selle info ette andma.

Transaktsiooni alustamiseks kasutatakse käsku BEGIN või BEGIN TRANSACTION. See ütleb andmebaasiserverile, et nüüd me alustasime transaktsiooniga ning sellest punktist edasi käsitle kõiki käske, mis me saadame, ühe tööühikuna. Näiteks:

BEGIN TRANSACTION

INSERT INTO user_log (USER_ID, DATE) VALUES (10, GETDATE())
SELECT @@IDENTITY

COMMIT

Transaktsiooni lõpetamiseks on kaks võimalust. On õnnelik lõpp ja õnnetu lõpp, sest transaktsioon võib lõppeda ka sellega, et senitehtu "keritakse tagasi" nagu poleks seda kunagi olnud. Seega siis muudatuste jõustamine ja tühistamine.

Muudatuste jõustamiseks anname käsu COMMIT või COMMIT TRANSACTION, muudatuste tühistamiseks on käsud ROLLBACK või ROLLBACK TRANSACTION.

BEGIN TRANSACTION

DELETE FROM users WHERE user_id> 10

ROLLBACK

Transaktsioonid erinevates andmebaasiserverites

Erievad andmebaasiserverid käsitlevad transaktsioone erinevalt. Kõik transaktsioonilised andmebaasiserverid, tahame me seda või ei, alustavad ja lõpetavad meie esitatud päringud transaktsioonide kontekstis. Tihti arvatakse ekslikult, et kui me oma rakenduse koodis transaktsioone ei kasuta, siis ei kasuta neid ka meie andmebaasiserver. Andmebaasiserver paraku siiski kasutab transaktsioone, lihtsalt me ise ei pruugi seda kuidagi tajuda.

Näiteks MySQL jookseb vaikimisi sellises imelises rezhiimis, kus iga päringu järel jõustatakse päringus tehtud muudatused selles transaktsioonis, mis antud päringu jaoks loodi. Analoogselt toimib ka MS SQL Server. Kuigi me ei ütle oma rakenduse koodis transaktsioonide kohta midagi, tehakse need ikkagi. Lihtsalt kõik eelpool kirjeldatu on meie silmade eest varjatud.

Selles mõttes on need kaks andmebaasiserverit nagu kaks tublit Alefit - moosipurk jõuab kenasti kapi peale ja Alef ronib taburetilt tühjade kätega maha.

Oracle peal on asjad natuke teisiti. Teha võib kõike, kuid tehtu jõustamiseks peame kindlasti andma käsu. Vastasel korral muudatused kaovad, sest vaikimisi on transaktsiooni lõpetamise käsuks ROLLBACK. Erinevalt siis eelmainitud serveritest.

Oracle on nagu ulakas Alef. Kui ta on pannud moosipurgi kapi peale, tuleb talle öelda, et jätku purk sinnapaika ja ronigu tabureti otsast alla. Kui seda ei ütle, on ta peatselt laua juures tagasi, näol moosivarga naeratus ning ta asetab isa ette lauale selle sama moosipurgi, mis kapi otsa pidi jõudma. Samas on see ka tema tugev külg - käsk mingid muudatused jõustada meenutab alati käskijale seda, et kui ta selle käsu annab, siis nii ka juhtub. Mine tea mitmeid kordi on see Oracle'i lähenemine päästnud firmasid adminide kiirustamisega kaasnevatest katastroofidest.

Transaktsioonid ja jõudlus

Transaktsioonide kasutamine tuleb läbi mõelda korralikult. Kui ühe transaktsiooni sisse aetakse tegevusi liiga palju, mõjutab see andmebaasiserveri jõudlust. Ja mitte vähe. Peamiselt esineb see probleem töölauarakendustes, kus rakenduse taustas on koguaeg püsti üks andmebaasi ühendus, mille kaudu andmeid tuuakse ja käske serveris käivitatakse.

Lõpetuseks

Transaktsioonide kasutamine võib muuta meie rakendused oluliselt paremaks ja töökindlamaks. Samuti arusaadavamaks ja kergemini hallatavamaks nii tehnikutele kui ka süsteemide ja andmebaaside administraatoritele. Lisapunktina saame ka ise paremini aru protsessidest, millega meie rakendus tegeleb ja milleks ta üldse loodud on.

Kommenteeri

sulge
Saada link e-postiga

© DT 2012 | Creative Commons Attribution-Noncommercial 3.0 License | WordPress