Transakce

Databáze jsou obvykle navržené pro práci více uživatelů. Stává se proto, že se snaží několik uživatelů naráz editovat stejná data. Jak se s tím vyrovnat? O tom pojednává tato kapitola (teoreticky). Jak na to prakticky popisuje kaptiola Transakce prakticky. Pochopením transakcí vaše znalosti o DBMS poskočí o další levely nahoru (a přitom je to tak jednoduché :-)).

Transakce

Transakce, zjednodušeně řečeno, je povel nebo sada povelů, které se buď provedou všechny a celé, nebo se neprovede vůbec nic. Transakce je nedělitelná (atomická) jednotka.

Každý jednotlivý SQL příkaz je transakcí. Tj. buď se provede celý, nebo nic. Toto platí, pokud jsou transakce podporovány. MyISAM tabulka z MySQL transakce nepodporuje, takže vám toto nezajišťuje.

Když spustíte nějaký příkaz, napříkad UPDATE, musí se provést celý nebo nic. To znamená, že když například updatujete 10 řádek, musí se změnit všech 10, nebo žádná. A to, i kdyby průběh příkazu přerušil výpadek proudu. DBMS si při provádění loguje změny (transakční protokol) a v případě, že dojde k nějaké havárii, je schopný z logu vrátit nedokončený příkaz (zruší všechny nepotvrzené operace).

Pokud jde o transakce s více SQL příkazy, představte si následující problém: Do banky příjdou dva požadavky na stržení peněz z účtu jednoho klienta. První požadavek si načte zůstatek klienta (a zjistí, že peněz má dost). O milisekundu později si načte zůstatek druhý požadavek. První požadavek odečte částku z načteného zůstatku a uloží ji. Totéž udělá o milisekundu i druhý požadavek. Výsledkem je, že je uložený výsledek druhého požadavku a stržení částky prvního požadavku zmizí. Tak takhle ne!

Nebo jiný příklad: chcete převést peníze z jednoho účtu na druhý. Nejdříve peníze z prvního účtu smažete. Pak se chystáte je připsat na druhý účet, ale v tom dojde k nějaké chybě a už se vám to nepodaří. Peníze nenávrantě zmizely. Tak tak by to taky nešlo. Buď se musí provést obojí (smazání z prvního účtu a připsání na druhý), nebo nic!

Začátek a konec transakce

Každá transakce má svůj začátek a konec. Transakce končí svým potvrzením (COMMITem).

Pokud pracuje databáze v tzv. auto commit režimu, pak je každý jednotlivý příkaz transakcí. Jeho spuštěním transakce začne a jeho dokončením se transakce automaticky ukončí (UPDATE začne updatováním prvního řádku a skončí updatem posledního řádku.)

Zajímavější je možnost vytvořit transakci z více příkazů. Prakticky se to dělá zahájením transakce příkazem BEGIN, pak spuštěním všech SQL příkazů, které mají být v rámci transakce (které se mají buď všechny provést, nebo žádný) a nakonec potvrzením transakce příkazem COMMIT.

Když nejste v auto commit režimu, pak (dle ANSI/ISO normy) transakce začne prvním SQL příkazem (po přihlášení k databázi) a automaticky se potvrdí (COMMITne) při bezchybném ukončení programu (když ho ukončíte sami, neukončí se nějakou chybou nebo výpadkem proudu atd.).
Když databáze selže, provede se automaticky zrušení celé transakce (ROLLBACK). Mimo to můžete samozřejmě potvrdit transakci kdykoliv příkazem COMMIT. (Následujícím SQL příkazem po COMMITu začíná nová transakce …).

ANSI/ISO norma po DBMS vyžaduje, aby byli součástí transakce všechny SQL příkazy. Realita je obvykle taková, že se v DBMS potvrzuje transakce jakýmkoliv SQL příkazem, který mění strukturu databáze (CREATE TABLE, ALTER TABLE …). (Takže nejen COMMITem). Důvodem je zřejmě velká náročnost, kterou by splnění požadavku ANSI/ISO normy vyžadovalo.

Souběh transakcí

Problémy, které mohou nastat při práci více uživatelů se stejnými daty lze rozdělit do následujících kategorií:

1. Problém ztracené aktualizace

Aktualizace jsou provedené bez vzájemného ohledu. V takovém případě platí poslední provedený UPDATE (DELETE …). Jde třeba o problém, který jsem popisoval v příkaldu se dvěma požadavky na stržení peněz z účtu jednoho klienta.

2. Problém nepotvrzených dat

Jde o tzv. nečisté čtení (dirty reading). Jde o problém, kdy si někdo přečte změny v datech, které jste ještě nepotvrdili (necommitli). Vy potom změny nepotvrdíte, ale ten kdo si je přečet je má za platné a pracuje s nimi.

3. Problém nekonzistentních dat

Jde o tzv. neopakovatelné čtení (nonrepeatable read). Během transakce provedete nějaký SELECT. Pak dál něco provádíte a mezi tím někdo provede (a commitne) změnu v databázi. Vy pak provedete (během jedné transakce) stejný SELECT a on vám vrátí jiný výsledek.

4. Problém přízračných dat

Aneb problém vložení přeludu (phantom read). Jde o podobný problém, jako u neopakovatelného čtení. Týká se však SELECTů s agregačními funkcemi.

Problém nekonzistentních datj lze technicky ošetřit například tak, že si DBMS pamatuje obsah řádků, na které jste se (v transakci) už ptali (které četl). Dotaz na stejný řádek vrátí stejné data.

Pokud se zeptáte na SUMu řádků z nějaké tabulky, DBMS si zapamatuje hodnoty v řádcích, ze kterých dělal SUMu. Když ale někdo mimo transakci vloží nový řádek a vy znovu provedete SUMu, bude tento nový řádek součástí výsledku – stejný SELECT vrátí jinou hodnotu.

Řešení souběhu transakcí

Izolace transakcí

  • v průběhu transakce je pohled na DB zcela konzistentní
  • v transakci nejsou vidět nepotvrzené změny jiných uživatelů
  • v transakci nejsou vidět potvrzené změny jiných uživatelů (potvrzené v průběhu izolované transakce)

Serializace transakcí

  • transakce A, B jsou spuštěny souběžně
  • DBMS zajistí, že výsledky budou stejné, jako by transakce A proběhla první a za ní transakce B (NEBO nejdřív B a pak A). To znamená, že druhá transakce v pořadí musí ovykle čekat na dokončení té první

Odstínění transakcí

  • skrytí nepotvrzených transakcí
  • skrytí transakcí potvrzených po zahájení aktuální transakce

Úrovně izolací definovaných standardem

Následující tabulka ukazuje úrovně izolací definovaných standardem a jaké konflikty daná úroveň povoluje:

1. 2. 3. 4.
READ_UNCOMITED NE ANO ANO ANO
READ_COMITED NE NE ANO ANO
REPEATABLE_READ NE NE NE ANO
SERIALIZABLE NE NE NE NE

Všiměte si, že žádná z úrovní izolací nedovoluje přepsat data dvěma souběžnými transakcemi. Důsledkem je, že pokud se jakýkoliv program v jakékoliv úrovni izolace pokusí přepsat/smazat data již přepsaná/smazaná, dojde k odvolání transakce (celá se zruší).

Vždycky musíte počítat s tím, že každá transakce může být odvolána! Když budete psát nějaký program, musíte takovou situaci ošetřit a pokusit se transakci provést znovu, nebo zobrazit uživeteli chybovou hlášku atd.

ACID

ACID je zkratka pro vlastnosti, které by měla databázová transakce splňovat:

  • A – Atomicity – buď se provede celá transakce, nebo nic.
  • C – Consistency – před a po dokončení transakce není porušeno žádné integritní omezení a data jsou konzistentní.
  • I – Isolation – výsledky příkazů uvnitř transakce jsou pro okolí neviditelné.
  • D – Durability – trvalost – pokud byla transakce potvrzena, pak jsou změny dat skutečně uložené a už nemohou být ztracené.

To by bylo k teorii transakcí asi tak všechno. V kapitole Transakce prakticky se dozvíte, jak se to všechno dělá v Postgresu (a dalších DBMS) prakticky. Tato kapitola ale není teoretická, takže je zařazena až v sekci pro pokročilé. Pokud jste ale nedočkaví, můžete na tu kapitolu přeskočit hned.

Komentář Hlášení chyby
Created: 28.1.2014
Last updated: 12.9.2015
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..