HELIA TIKO-05 SQL-TRANSAKTIOT 1 ( 12) SQL-transaktiot Lähes kaikissa tietojärjestelmissä tietojen talletus on toteutettu tietokannoissa, joita käytetään tietokannanhallintajärjestelmien (DBMS) palvelujen avulla. Nykyiset DBMS-järjestelmät ovat teknisesti vaativia, pitkälle kehitettyjä, tiedot turvaavia ja oikein hoidettuina vankkoja talletetun tiedon varastojärjestelmiä. Ne muodostavat vankan perustan luotettaville sovelluksille, mutta kuitenkin vain sillä edellytyksellä, että niiden palveluita osataan käyttää oikein. DBMS-järjestelmän palvelua käytetään oikeaoppisesti jakamalla sovelluksen käyttämän tietokannan käsittely SQL-transaktioiksi, joissa sovelluksen tietokantaistunnon (connection, SQL-session) yksi tai useampi perättäinen SQLkomento on rajattu käsittelykokonaisuudeksi, joka transaktion lopussa kuitataan suoritetuksi (COMMIT) tai peruutetaan kokonaan (ROLLBACK). SQL-standardin mukaan tietokantakäsittely on aina transaktionaalista ja transaktion aloittaa SQListunnon alun tai viimeksi committoidun taikka peruutetun transaktion jälkeen ensimmäinen suorittava (ei esim. DECLARE) SQL-komento. Joissakin DBMS-järjestelmissä (esimerkiksi SQL Serverissä) transaktio tulee aloittaa eksplisiittisesti BEGIN TRANSACTION komennolla tai muuten käsittely tapahtuu ns. AUTOCOMMIT-moodissa, missä jokainen onnistunut SQL-komento committoituu automaattisesti ja sitä ei siis voi enää peruuttaa ROLLBACK-palvelulla. Keskitymme nyt vain transaktionaaliseen käsittelyyn. Tyypillinen esimerkki transaktiosta on tilisiirto-operaatio, missä nostetaan joku summa (esimerkiksi 100 euroa) yhdeltä pankkitililtä ja talletetaan se toiselle tilille: UPDATE Tilit SET saldo = saldo 100 WHERE tilino = 101202; UPDATE Tilit SET saldo = saldo + 100 WHERE tilino = 220330; COMMIT WORK; Jos järjestelmissä sattuisi joku toimintahäiriö ennen toisen UPDATE-komennon suoritusta ilman transaktionaalista käsittelyä, olisi 100 euroa hävinnyt tuhkatuuleen. Oikeaoppisesti transaktionaalisesti suoritettuna ensimmäinenkin UPDATE-komento peruuntuisi automaattisesti toimintahäiriöstä toivuttaessa, joten tietokantaan ei jää ristiriitaista tietoa. Oikeaoppista SQL-transaktiota sanotaan ACID-transaktioksi, missä sanan kirjaimet tulevat seuraavien englanninkielisten transaktion ominaisuuksien alkukirjaimista: Atomic Consistent Isolated atominen eli jakamaton operaatiosarja, joka tulee kokonaan joko suoritetuksi (committed) tai automaattisesti perutuksi (rolled back). operaatiosarja siirtää tietokannan ehyestä, ristiriidattomasta tilasta toiseen ehyeen tilaan. Tämän ominaisuuden mekaaninen DBMS:n vastuuta painottava tulkinta tarkoittaa ettei tietokannan eheysrajoitteita (constraints) voida rikkoa transaktiossa. Laajempi tulkinta siirtää vastuun myös sovellusohjelmalle: transaktion ohjelmalogiikan tulee olla hyvin muodostettu ja testattu (well formed transaction). transaktio käsittelee tietokannan tietoja eristyneenä ilman samanaikaisen muun käsittelyn aiheuttamia sivuvaikutuksia. Käsittelyn sanotaan olevan sarjallistuvaa (serialized). Tämä tarkoittaa, että DBMS:n tulee sarjallistaa
HELIA TIKO-05 SQL-TRANSAKTIOT 2 ( 12) Durable samanaikaisten ACID-transaktioden operaatiot siten, että näiden lopputulos tietokannassa vastaa tilannetta, jossa nämä samanaikaiset transaktiot olisi suoritettu jossakin peräkkäisessä järjestyksessä. Huom: tämä ei tarkoita, että DBMS käsittelisi nämä transaktiot peräkkäin! committoidun transaktion tiedot säilyvät tietokannassa (ellei niitä muuteta jossakin myöhemmässä käsittelyssä). ACID-periaate edellyttää, että DBMS ei voi committoida transaktiota, joka ei täytä näitä vaatimuksia. Joko DBMS:n tai sovelluksen on peruttava vaatimukset rikkova transaktio. Näistä Isolated-vaatimus on haasteellinen ja voi johtaa sarjallistuvuuskonflikteihin tai suoritustehoa haittaaviin odotusaikoihin. Transaktion kirjoittamaa tietoa ei transaktionaalisessa käsittelyssä nykyjärjestelmissä voida muuttaa muiden transaktioiden toimesta ennen transaktion päättymistä eli transaktion aikana sen itsensä tekemä päivitys ei voi hukkua (lost update problem on tässä mielessä ratkaistu). SQL-standardi ei ota kantaa käsittelyn eristyvyyden toteutukseen, mutta määrittää sovelluksen kannalta luettavalle tiedolle Isolated-vaatimuksesta tingittävät eristyvyyden palvelutasot eli Isolation Levels: Read Uncommitted sallii eristämättömän tietojen lukemisen eli tietokannasta voidaan lukea samanaikaisten transaktioiden kirjoittamaa keskeneräistä tietoa (dirty read). Read Committed Repeatable Read Serializable luetaan vain committoitua tietoa. Jos joku toinen transaktio on varannut tiedon päivitettäväksi, jäädään lukituksia käyttävissä DBMS-järjestelmissä odottamaan tämän toisen transaktion päättymistä. luetaan vain committoitua tietoa ja varataan kaikki luetut tiedot mahdollista uudelleenlukemista varten aina transaktion loppuun asti. Transaktion loppuun pidettävillä lukulukoilla estetään tiedon muuttuminen muiden transaktioiden toimesta transaktion aikana. luetaan vain committoitua tietoa ja DBMS:n tulisi pitää tietokanta transaktion kaikkien tarvitsemien tietojen osalta alkuhetken mukaisessa tilassa niin ettei transaktion aikana kantaan ilmaannu muiden transaktioiden toimesta sellaista uutta tietoa (phantom, suomeksi kummitus), jota tämä transaktio olisi voinut tarvita, mutta tieto olisi jäänyt tältä transaktiolta huomaamatta. Vain tämä toteuttaa yleispätevästi ACID-periaatteen mukaisen Isolated-eristyvyyden. Eristyvyyden toteutukseen nykyiset DBMS-järjestelmät käyttävät pääasiassa kahta menetelmää: - Luku- ja kirjoituslukkojen protokolla, yksinkertaistettuna seuraava: Kirjoitusoperaatioita varten DBMS jonottaa transaktiolle X-lukon (exclusive mode) eli rivin kirjoituslukon, jonka voi saada vain jos riviin ei muilla transaktioilla ole kirjoitus- eikä lukulukkoja. Lukuoperaatioita varten DBMS jonottaa transaktiolle S-lukon (Shared mode) eli rivin lukulukon, jonka voi saada aina jos riviin ei ole jollakin toisella X-lukkoa. Todellinen lukitusprotolla on monimutkaisempi kattaen muitakin lukitusmoodeja ja muitakin lukitustasoja kuin rivilukitukset. Tätä protokollaa käyttävät mm. DB2-järjestelmät ja SQL Server 2000. Protokolla on kuvattu Jim Grayn ja Andreas Reuterin kirjoittamassa klassikossa Transaction Processing: Concepts and Techniques ja suppeammin sitä käyttävien järjestelmien käsikirjoissa. - Rivien moniversiointi: riviä päivitettäessä siitä kirjoitetaan sukupolviversio estäen kuitenkin kilpailevien versioiden syntyminen. Muut voivat lukea transaktionsa alkuhetkellä voimassa olleen riviversion. Tätä protokollaa käyttävät mm. Solid ja Mimer.
HELIA TIKO-05 SQL-TRANSAKTIOT 3 ( 12) Oracle käyttää näiden yhdistelmää: saman rivi päällekkäiset päivitykset estäviä kirjoituslukkoja ja näyttäen päivitettävää riviä lukeville samanaikaisille transaktioille rivin aikaisempaa versiota. Eristyvyyden toteutustekniikasta riippuen järjestelmät tukevat usein vain osaa SQL-standardin eristyvyystasoista: - Rivien moniversiointi mahdollistaa vain Read Committed ja Serializable -tasot. Solid ja Mimer tukevat siis vain näitä. - Oracle sanoo tukevansa vain Read Committed ja Serializable -tasoja, mutta sen Serializabletulkinta on erilainen kuin SQL-standardin ja Oraclen tulkinnan mukaisesta isolated-eristyvyydestä käytetään nimitystä Snapshot Isolated. - SQL Server 2000 tukee kaikkia SQL-standardin eristyvyystasoja ja SQL Server 2005 näiden lisäksi myös Snapshot Isolated tasoa. - DB2 tukee SQL-standardin mukaisia eristyvyystasoja, joskin eri nimisinä käyttäen Read Committed tason asemesta currentin rivin lukulukon säilyttävää Cursor Stability eristyvyyttä. Sarjallistuvuusongelmista Sarjallistuvuusongelmia aiheuttavat mm. seuraavat - saman rivin kilpailevat käsittelyt, joissa rivi luetaan ennen sen päivitystä (mikä on aivan tyypillinen tilanne) - eri kohteisiin kilpailevien transaktioiden eri järjestyksessä yrittämät käsittelyt, esimerkiksi tilisiirrot vastakkaisiin suuntiin. Tyypillinen sarjallistuvuusongelma lukitsevissa järjestelmissä ilmenee tilanteena, missä kaksi tai useampi transaktio odottaa toisiaan kehässä ja näiden suoritus pysähtyy. Tilannetta kutsutaan lukkiumaksi (deadlock). Nykyiset DBMS-järjestelmät huomaavat lukkiumatilanteen muutamassa sekunnissa. DB2 ja SQL Server purkavat tilanteen valitsemalla yhden toisiaan odottavista transaktioista yhden lukkiuman uhriksi ja tekevät tälle automaattisesti ROLLBACKin. Oracle havaitsee lukkiuman uhkan ja peruuttaa automaattisesti komennon, joka johtaisi lukkiuma tilanteeseen. Asianomainen sovellus saa tästä virheilmoituksen ja tyypillisesti antaa itse ROLLBACK-komennon, koska ei voi viedä transaktiotaan loppuun. Tarkastelemme seuraavassa esimerkkiä samasta rivistä kilpailevia transaktioita, joissa rivi luetaan ennen sen päivitystä, ja miten sarjallistuvuusongelma ilmenee SQL Server 2000:lla, Solidilla ja Oracle 9.2:lla testattuna: Luodaan ensin taulu Tilit ja lisätään sinne pari riviä CREATE TABLE Tilit ( Tilino INTEGER NOT NULL PRIMARY KEY, Saldo INTEGER NOT NULL ); INSERT INTO Tilit (Tilino,Saldo) VALUES (101202,10000); INSERT INTO Tilit (Tilino,Saldo) VALUES (220330,20000); COMMIT WORK; Avataan 2 samanaikaista SQL-istuntoa A ja B ja kokeillaan näissä seuraavia operaatioita kirjoitetussa järjestyksessä -- Asiakas A SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT Saldo FROM Tilit WHERE Tilino = 220330;
HELIA TIKO-05 SQL-TRANSAKTIOT 4 ( 12) -- Asiakas B SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT Saldo FROM Tilit WHERE Tilino = 220330; -- laskee 20000 +2000 = 22000 UPDATE Tilit SET Saldo = 22000 WHERE Tilino = 220330; -- Asiakas A -- laskee 20000 +3000 = 23000 UPDATE Tilit SET Saldo = 23000 WHERE Tilino = 220330; SQL Server 2000:lla testattuna sarjallistuvuus ongelma laukeaa DBMS:n toimesta tehdyllä lukkiuman (deadlock) purkamisella
HELIA TIKO-05 SQL-TRANSAKTIOT 5 ( 12) Solid Embedded Engine 4.1 havaitsee sarjallistuvuusongelman (concurrency conflict)
HELIA TIKO-05 SQL-TRANSAKTIOT 6 ( 12) Oracle 9.2:llä Read Committed eristyvyystasolla päädyttäisiin hukattuun päivitykseen (testaa tämä itse harjoituksena). Oraclen SERIALIZABLE eristyvyydellä (oikeasti siis Snapshot Isolated) transaktiot käyttäytyvät seuraavasti: A:n UPDATE jää odottamaan B:n lukon vapautumista ja kun B committoi selviää ettei A:n päivitys voi sarjallistua:
HELIA TIKO-05 SQL-TRANSAKTIOT 7 ( 12) Vastaava koejärjestely selainpohjaisella Oraclen isqlplus-käyttöliittymällä kestää... mutta päätyy lopulta samaan tulokseen
HELIA TIKO-05 SQL-TRANSAKTIOT 8 ( 12) Transaktioiden suunnittelusta Transaktiolla sovellus kommunikoi tietokantapalvelimen kanssa hakien tietoa käsiteltäväksi tai kirjaten tietokantaan sovelluksesta välittyviä tietoja. Transaktiolla tulee olla selvä tehtävä. Transaktiolla toteutetaan tyypillisesti käyttöliittymässä tehty valinta hae tai talleta. Transaktioon ei tule sisältyä kommunikointia käyttäjän kanssa, sillä tällöin transaktio varaa tietokannan resursseja liian pitkään haitaten muiden tietokantakäsittelyä. Yleensäkin tulee pyrkiä lyhyiden transaktioiden toteutuksiin. Sarjallistuvuuskonfliktiin kaatunut transaktio ei käynnisty DBMS:n toimesta uudelleen, vaan sovelluksen kannattaa yrittää sitä muutama kerta uudelleen ennen ongelman raportoimisesta käyttöliittymään.
HELIA TIKO-05 SQL-TRANSAKTIOT 9 ( 12) Tietokannan toipuminen (Recovery) (ks RdbmsRecovery.ppt) DBMS-järjestelmät numeroivat tietokannan transaktiot ja kirjoittavat transaktiolokiin jokaisesta tietokannassa muutetusta rivistä asianomaisella transaktionumerolla merkityn tietueen, johon tulee rivin alkukuva (before image) ennen käsittelyä ja loppukuva (after image) käsittelyn jälkeen. INSERT-komennon tapauksessa alkukuva on tyhjä ja DELETE-komennon tapauksessa loppukuva on tyhjä. COMMIT ja ROLLBACK-komennoista kirjoitetaan lokiin myös tietueet ja transaktion lokitietueet kirjoitetaan puskureista transaktiolokiin viimeistään tässä vaiheessa. Ajoittain DBMS tekee CHECKPOINT-operaation, jossa puskurialtaan muuttuneet sivut kirjoitetaan tietokantatiedostoihin ja transaktiolokiin kirjoitetaan checkpoint-tietue, jossa on lista kaikista käynnissä olevien transaktioiden numeroista. Huom: Jos tietokannanhoitaja sulkee tietokantainstanssin hallitusti eli ei salli kantaan uusia istuntoja ja odottaa että kaikki käynnissä olevat istunnot ovat päättyneet, kirjoittaa DBMS lopuksi transaktiolokiin checkpoint-tietueen, jossa on tyhjä transaktionumerolista. Tarkastelemme nyt tilannetta, jossa tietokantainstanssi tai koko palvelin kaatuu esimerkiksi sähkökatkoksen vuoksi. Tietokannan kannalta kaikki levyillä olevat tiedostot säilyvät, mutta kaikki puskurialtaan tiedot menetetään (ns. Soft Crash tilanne). t c t f time T1 T2 Commit Rollback T3 T4 T5 Checkpoint record Commit Soft Crash System Failure Kun DBMS seuraavan kerran käynnistetään, se etsii ensitöikseen transaktiolokin viimeisen checkpoint-tietueen. Jos tämä osoittaa, että DBMS on suljettu hallitusti, käynnistetään sovellusten palvelu, muussa tapauksessa DBMS yrittää ensin toipua Soft Crash tilanteesta Rollback Recovery operaatiolla seuraavasti: Checkpoint-tietueen transaktionumerot kirjataan peruutettavien transaktioiden ns. UNDO-listalle ja uudelleen kirjoitettavien transaktioiden ns. REDO-lista on aluksi tyhjä. DBMS käy transaktiolokin läpi chekcpoint-tietueesta lokin loppuun asti kirjaten kaikki alkaneet transaktionumerot UNDO-listalle
HELIA TIKO-05 SQL-TRANSAKTIOT 10 ( 12) ja siirtäen UNDO-listalta kaikki lokin perusteella committoitujen transaktioiden numerot REDOlistalle. Lopuksi DBMS käy transaktiolokin läpi lopusta alkuun päin kirjoittaen UNDO-listan transaktioiden rivien alkukuvat tietokantaan ja vastaavasti kirjaten tietokantaan REDO-listan transaktioiden rivien loppukuvat transaktiolokin mukaisessa aikajärjestyksessä. Rollback recovery using transaction log t c t f time T1 T2 Commit Rollback T3 T4 Commit T5 Checkpoint record Rollback Recovery Undo list: T1, T2, T3, T4, T5 Redo list: T1, T4 5. Rollback transactions of the Undo list - writing the before images into the database Redo transactions of the Redo list - writing the after images into the database 6. Open the DBMS service to applications DBMS voi nyt avata viimeiseen committoituun transaktioon asti toipuneen tietokannan sovellusten käyttöön.
HELIA TIKO-05 SQL-TRANSAKTIOT 11 ( 12) HARJOITUKSET Harjoitus 1. Sarjallistuvuus: Kilpailu yhdestä resurssista Luo Info9-palvelimen Oracle 9.2-asennuksen TUX1-instanssiin edellä tarkasteltu Tilit-taulu. Toista edellä kuvattu tilin 220330 saldon samanaikainen kasvatus transaktiolla A ja B käyttäen Oraclen eristyvyystasoa Read Committed. Seuraako tästä konflikti vai oikea tulos? Harjoitus 2. Sarjallistuvuus: Kilpailu kahdesta resurssista Testaa kahdessa rinnakkaisessa selainikkunassa ristikkäiset tilisiirrot missä transaktio A siirtää 100 euroa tililtä 101202 tilille 220330 ja transaktio B yrittää siirtää samanaikaisesti 200 euroa tililtä 220330 tilille 101202. Kokeile testiä Oraclen eristyvyystasoilla Read Committed ja Serializable. Onko tuloksissa eroa? Harjoitus 3. Rollback Recovery (tuntiharjoitus / demo) (ks SoliServerRecovery.ppt ja käsikirjoitus: transactions.txt) Tutustutaan opettajan opastuksella Solid Embedded Engine järjestelmään. Käynnistetään työasemaan Solid-palvelin ja käynnistetään tämän jälkeen Solid Flowcontrol ohjelma SQL-editoriksi. Luodaan ensin DBA-käyttäjänä tietokantaan oma käyttäjätunnus CREATE USER ict03d-xx-nn IDENTIFIED BY ict03d; Sulkematta DBA:n istuntoa avataan uusi connection -ikkuna tällä omalla käyttäjätunnuksella ja luodaan Rtest-taulu ja poistetaan ruksi ikkunan oikeassa alanurkassa olevasta AutoCommit valinnasta. Aloitetaan ikkunassa transaktio T1 lisäten tauluun Rtest käsikirjoiituksen mukainen rivi. Avataan Flowcontrol-ohjelmassa transaktioita T2-T5 varten vielä 4 muuta rinnakkaista ikkunaa poistaen jokaisesta AutoCommit-tila. Edetään käsikirjoituksen mukaan lisäten rivejä ao. transaktioissa tauluun Rtest. Käsikirjoituksen mukaisessa kohdassa palataan DBA:n istuntoon ja suoritetaan komento ADMIN COMMAND 'makecp' mikä saa aikaan Solidin checkpoint-operaation. Jatketaan rivien lisäämistä käsikirjoituksen mukaan. Lopulta käynnistetään Windowsin Security ikkunasta Task Manager ja simuloidaan järjestelmän kaatumista kaatamalla Solid Embedded Engine.
HELIA TIKO-05 SQL-TRANSAKTIOT 12 ( 12) Käynnistetään Solid Embedded Engine uudelleen Start Programs Solid.. valikosta. Tämä raportoi messageboxissa transaktioiden recovery-operaatiosta. FlowControl-ohjelman ikkunoiden istunnot ovat poikki, mutta avataan uusi connection omalla tunnuksella ja katsotaan SELECT-komennolla taulun Rtest sisältö. Mitkä rivit taulusta löytyvät ja miksi?