ACID znaci poziadavky na korektnost transakcie
- Atomicity, oznacuje poziadavku na beh transakcie - bud cela, alebo vobec
- Consistency, vyjadruje, ze transakcia transformuje DB z konzistentneho stavu do konzistentneho stavu
- Independence, nezavislost jednej transakcie na druhej. Teda, ciastocne efekty jednej DB nie je viditelna inym transakciam
- Durability, je poziadavka na persistentne ulozenie vysledkov po uspesnom vykonani transakcie
Transakcie su vyuzite vo vacsine dnesnych DBMS. Zaciatok transakcie musi byt implicitne oznaceny tak, ako aj koniec transakcie.
V pripade bezproblemoveho priebehu transakcie sa vysledku ulozia prikazom COMMIT, alebo zrusia prikazom ROLLBACK. Commit a rollback mozu byt vyvolane implicitne systemom, alebo explicitne uzivatelom.
transakce PříkazKÚhradě(kolik, zÚčtu, naÚčet)
{
SELECT Zůstatek INTO X FROM Účty WHERE čÚčtu = zÚčtu.
if (X < kolik) ZrušTransakci(“Malý zůstatek na účtu!!”);
UPDATE Účty SET Zůstatek = Zůstatek – kolik WHERE čÚčtu = zÚčtu;
UPDATE Účty SET Zůstatek = Zůstatek + kolik WHERE čÚčtu = naÚčet;
PotvrďTransakci;
}
V pripade incidentu (alebo chybnom vykonani transakcie) musi dojst k naprave. K tomu mozme vyuzit operacie typu
- UNDO, cim zrusime transakciu, ktora prebehla len ciastocne
- REDO, cim zopakujeme transakciu
Transakcia sa moze pocas behu nachadzat v piatich stavoch. Zacne ako Aktivna, a odtial sa posunie do stavu do Partially Commited alebo Fail. Stav C znamena Commit, kedy je transakcia uspesne potvrdena a stav AB oznacuje ABort alebo Rollback (problem terminologie).
Okrem toho, ze musi byt zarucene splnenia podmienok ACID, tak musi byt spravne vyrieseny a zabezpeceny aj pripadny pararelny priebeh viacerych transakcii. Pokial sa transakcie vykonavaju pararelne, tak moze dojst k roznym typickym neduhom konkurentneho pristupu a to nazyvame konflikt.
- strata aktualizacie - hodnota, ktoru T2 nacita je zmenena v T1 pred tym, ako T2 ulozi svoj vysledok
- docasna aktualizacia - vznika pry chybe systemu, ked sa v T1 stane chyba a vykona sa rollback, tak v T2 dojde k tomu, ze nebude mat spravne hodnoty
- nekorektne pouzitie agregacnej funkcie je vlastne to iste, ako strata aktualizacie
- neopakovatelne citanie - T2 sa snazi opakovane cist hodnotu, ktoru uz pred tym precitala, ale tentokrat je ina, pretoze ju T1 zmenila
- fantom - T2 vyberie mnozinu riadkov a T1 ju zmeni, T2 vykonava operacie na neaktulizovanych datach a po opatovnom nacitani bude mnozina riadkov ina
Aby sme konfliktom zabranili, tak vyuzivame rozvrhu, ktory ma na starosti rozvrhovac. Rozvrhovac sluzi k rozvrhovaniu danej mnoziny transakcii.
Rozvrhy, ktore su vytvarane dynamicky, to znamena, ze existujuci rozvrh moze byt doplneny dalsou transakciou (prelozeny) sa nazyvaju prekladane.
Rozvrh moze byt seriovy, kde transakcie bezia jedna za druhou. Pocet moznych usporiadani serioveho rozvrhu je |S|!. Seriovy rozvrh urcuje tzv, sekvencne poradie vykonania transakcii.
Prekladane rozvrh zarucuje istu formu pararelilizmu, kedy sa "prazdne miesto", napriklad cakanie na nacitanie stranky da vyuzit dalsou transakciou na vypocty a pod. Zaroven mame moznost uprednostnit rychle transakcie a nie su tak brzdene pomalymi.
Usporiadatelnost rozvrhu je jednou z poziadavok na korektny rozvrh. Rozvrh je usporiadatelny, ak jeho vykonanie vedie ku konzistentnemu stavu DB a teda k tomu istemu stavu, k akemu dospejeme seriovym vykonanim rovnakych transakcii.
Konflikty, ktore sme vymenovali vyssie su sposobene prave prekladanim transakcii a preto potrebujeme vytvorit rozvrh tak, aby bol konfliktovo usporiadatelny. Taky rozvrh je konfiktovo usporiadatelny, ak je konfliktovo ekvivalentny seriovemu rozvrhu. To znamena, ze v nom nie su konflikty.
Rozvrh je konfliktovo usporiadatelny, ak je jeho precedencny graf acyklicky. Precedencny graf je orientovany graf, kde uzly predstavuju potvrdene transakcie a hrany konflikt.
Konflikty a usporiadatelnost je postacujuca, pokial hovorime o statickej povahe DB (bez vkladania a mazania objektov). Pokial pripustime dynamicku povahu DB, tak sa musime este zaoberat fantomovym javom.
Zostava nam este jedna vec v statickych rozvrhoch. Rozvrh by mal byt zotavitelny, co znamena, ze transakcia T je potvrdena az po tom, ako su potvrdene vsetky ostatne transakcie, ktore zmenili data, ktore boli neskor citane a zapisovane v T. Inak, by sme pri ruseni jednej z transakcii museli prikrocit ku kaskadovemu ruseniu transakcii.
Ked rozvrhovac rozvrhuje, tak vyuziva protokoly, ktore zarucuju zachovanie pozadovanych vlastnosti rozvrhu. Vyuzivaju sa uzamykacie protokoly, ktore su postavene na uzamykani pristupu a alternativne protokoly, ktore vyuzivaju casove razitka.
Uzamykaci protokol je prikladom pesimistickeho protokolu, ktory vyuziva uzamykanie entit a takto zarucuje konfliktovu usporiadatelnost rozvrhu. Zamkami je pevne dane poradie transakcii (alebo aspon pristupu). Uzamykanie entit moze byt
Prikladom uzamykacieho protokolu moze byt 2-fazovy uzamykaci protokol 2PL.
v SQL 99 vyzera start transaction statement asi takto:
<start transaction statement> ::=
START TRANSACTION <transaction mode> [ { <comma>
<transaction mode> }...]
<transaction mode> ::= <isolation level>
| <transaction access mode>| <diagnostics size>
<transaction access mode> ::= READ ONLY | READ WRITE
<isolation level> ::= ISOLATION LEVEL <level of isolation>
<level of isolation> ::= READ UNCOMMITTED
| READ COMMITTED | REPEATABLE READ
| SERIALIZABLE
<diagnostics size> ::=
DIAGNOSTICS SIZE <number of conditions>
<number of conditions> ::= <simple value specification>
Uzamykaci protokol je prikladom pesimistickeho protokolu, ktory vyuziva uzamykanie entit a takto zarucuje konfliktovu usporiadatelnost rozvrhu. Zamkami je pevne dane poradie transakcii (alebo aspon pristupu). Uzamykanie entit moze byt
- exkluzivne - entita je uplne uzamknuta, citat a zapisovat moze len vlastnik zamku a takyto zamok moze byt prideleny len jednej transakcii
- zdielane - entita je uzmaknuta len pre zapis. Takyto zamok moze byt prideleny vicerym transakciam
Ak transakcia pozaduje zamok, ktory nie je k dispozicii, tak je suspendovana a caka na pridelenie. Tento mechanizmus je uzivatelovi skryty.
Uz som spomenul, ze v dynamickej databaze dochadza k fantomovemu efektu. To znamena, ze pokial jedna transakcia pracuje s mnozinou entit a druha tuto mnozinu logicky meni (pridava/odobera), tak to moze mat za nasledok nekonzistenciu databaze. Preto uzamykame cele tabulky. Ak v tabulkach existuju indexy na entitach, tak mozme checkovat fantoma na urovni indexu
Uzamykanie sa riesi pomocou spravcu zamku, tzv lock managera, co je vlastne tabulkou zamkou. V priklade nizsie je U(T) pouzite ako prikaz unlock, S(T) ako shared lock tabulky T a X(T) je exkluzivny zamok tabulky T.
Prikladom uzamykacieho protokolu moze byt 2-fazovy uzamykaci protokol 2PL.
- transakcia moze modifikovat/citat A, ak obdrzala exkl. zamok A
- transakcia nemoze pozadovat ziaden zamok, ak uz nejaky mala a uvolnila ho
Striktny 2PL rozsiruje druhe pravidlo na "kazdy zamok je uvolneny po ukonceni transakcie", co garantuje zotavitelnost a zabezpecenie proti kaskadovemu ruseniu transakcii.
Pri zpracovani rozvrhu moze dojst k deadlocku. Napriklad T1 caka na zamok T2 a T2 caka na uvolnenie zamku T1. Riesime to napriklad tak, ze pokial transakcia dlho caka na zamok, tak asi uviazla a zrusime ju. Mozme pouzit waits for graph, ktory periodicky testovany na cyklus. Ak nastane uviaznutie, tak zrusime jednu transakciu v cykle a to tu, ktora
- ma najmensi pocet zamkov
- vykonala najmenej prace
- ma najdalej k dokonceniu
Uviaznutiu mozme predist prioritnym uprednostnovanim, alebo pouzitim konzervativnym 2PL protokolu.
Prikazy SQL pre transakciu maju takyto syntax
<SQL transaction statement> ::=
<start transaction statement>
|<set transaction statement>
| <set constraints mode statement>
| <savepoint statement>
| <release savepoint statement>
| <commit statement>
| <rollback statement>
<SQL transaction statement> ::=
<start transaction statement>
|<set transaction statement>
| <set constraints mode statement>
| <savepoint statement>
| <release savepoint statement>
| <commit statement>
| <rollback statement>
v SQL 99 vyzera start transaction statement asi takto:
<start transaction statement> ::=
START TRANSACTION <transaction mode> [ { <comma>
<transaction mode> }...]
<transaction mode> ::= <isolation level>
| <transaction access mode>| <diagnostics size>
<transaction access mode> ::= READ ONLY | READ WRITE
<isolation level> ::= ISOLATION LEVEL <level of isolation>
<level of isolation> ::= READ UNCOMMITTED
| READ COMMITTED | REPEATABLE READ
| SERIALIZABLE
<diagnostics size> ::=
DIAGNOSTICS SIZE <number of conditions>
<number of conditions> ::= <simple value specification>
Zaujimavy je isolation level, ktory definuje styri urovne izolacie na zaklade troch neziaducich javov
- Dirty Read, strata aktualizacie
- Nonrepeatable Read, alebo neopakovatelne citanie
- Phantom
Doporucujem:
http://www.root.cz/clanky/transakce-a-izolace-transakci-v-databazich/