Řízení transakcí a zamykání
Transakce
Transakce je logická jednotka práce v databázovém systému. Jedna transakce se skládá z jedná či několika databázových operací (např. čtení, zápis, aktualizace), které z pohledu uživatele tvoří jeden celek.
Platí zde zásadní pravidlo atomicity (všechno nebo nic):
- buďto se provedou všechny operace v transakci (úspěšně)
- nebo se neprovede vůbec nic (nastane-li chyba, databáze se vrátí po stavu před samotným začátkem transakce)
Pro ovládání transakcí používá SŘBD následující příkazy:
- START TRANSACTION (zahájení) – označuje začátek transakce (v některých verzích SQL též BEGIN); SŘBD v tento moment vytvoří SAVEPOINT (záchytný bod, ke kterému se lze vrátit v případě chyby)
- COMMIT (potvrzení) – úspěšné ukončení transakce; všechny změny provedené v rámci transakce se podařilo trvale zapsat do databáze (trvale = durability)
- ROLLBACK (návrat) – neúspěšné ukončení || storno – všechny změny od začátku BEGIN (nebo od posledního SAVEPOINTu) jsou zahozeny
Transakce během svého provádění postupně prochází několika stavy. Pochopení těchto stavů je klíčové pro případnou diagnostiku chyb, ke kterým může v databázovém systému docházet.
- active (aktivní) – výchozí stav; transakce právě probíhá, vykonávají se jednotlivé operace
- partially committed (částečně potvrzená) – došlo k vykonání poslední operace, ale data ještě fyzicky nejsou zapsána na disk (nacházejí se např. v operační paměti) – čeká se na finální potvrzení
- committed (potvrzená) – úspěšné ukončení, data jsou bezpečně a trvale zapsána, transakce končí
- failed (chybná) – nastala chyba (např. porušení integrity dat, deadlock, atp.) – transakce nemůže být dokončena a musí být zrušena
- aborted (zrušená) – stav po provedení ROLLBACKu – transakce odstranila všechny částečně potvrzené změny a systém se nachází ve stavu, jako kdyby transakce ani nikdy nezačala

Příklady
Scénář 1 – Adam posílá Evě 1000 Kč.
počáteční stav účtu Adam: 5000 Kč, počáteční stav účtu Eva: 2000 Kč
| Krok | Operace / SQL příkaz | Stav transakce | Co se děje v systému |
| 1. | START TRANSACTION | active | Systém zahajuje transakci. Vytváří se virtuální „stav“, ve kterém se změny dějí, ale zatím nejsou vidět navenek. |
| 2. | UPDATE Ucty SET castka = castka - 1000 WHERE klient = 'Adam'; | active | Adamovi se v paměti odečetlo 1000 Kč. Pozor: V databázi na disku má Adam stále 5000, změna je jen v transakčním logu/paměti. |
| 3. | UPDATE Ucty SET castka = castka + 1000 WHERE klient = 'Eva'; | partially committed | Poslední operace proběhla. Systém zkontroloval, že oba příkazy jsou syntakticky správně a že je lze provést. |
| 4. | COMMIT | committed | „Razítko“. Systém zapíše změny trvale na disk. Uvolní se zámky na účtech Adama a Evy. |
| 5. | Konec procesu | committed / finished | Ostatní uživatelé nyní vidí, že Adam má 4000 Kč a Eva 3000 Kč. |
Díky tomu, že transakce proběhla celá (obě operace), je systém stále v konzistentním stavu. Peníze se přesunuly a nikam se neztratily.
Scénář 2 – Chyba během provádění transakce
Zákazník si chce v e-shopu objednat poslední kus notebooku, ale během procesu dojde k porušení logiky databáze (například dojde k chybě sítě nebo k chybě při zápisu na disk).
Cíl: vytvořit novou objednávku, přidat do ní zboží a odečíst kus ze skladu.
| Krok | Operace / SQL příkaz | Stav transakce | Co se děje v systému |
| 1. | START TRANSACTION | active | Zahájení transakce. |
| 2. | INSERT INTO Objednavky (zakaznik, datum) VALUES ('Petr', NOW()); | active | Vytvořil se záznam s objednávkou. Systém tento záznam zamkne. |
| 3. | INSERT INTO ObjednavkyPolozky (ID, zbozi) VALUES (LAST_INSERT_ID(), 'Notebook'; | active | Vytvořil se záznam s položkou objednávky. Systém tento záznam zamkne. |
| 4. | UPDATE Sklad SET pocet = pocet - 1 WHERE zbozi = 'Notebook'; | active | Sklad se snížil na 0. Zatím vše vypadá dobře. |
| 5. | CHYBA! (Výpadek sítě) | failed | Představme si situaci: Databáze zjistí, že během kroku 4 dojde k chybě zápisu na disk. Systém hlásí: „Nelze pokračovat.“ |
| 6. | Automatická reakce systému | failed -> aborted | Protože nelze provést COMMIT, systém musí vyčistit „rozpracovanou práci“. Spustí se ROLLBACK. |
| 7. | ROLLBACK (Automaticky) | Zrušená | Systém se podívá do logu a vrátí změny zpět: 1. Vrátí počet kusů na skladě na 1. 2. Smaže (odvolá) vytvořený záznam v Objednávkách. 3. Smaže (odvolá) vytvořený záznam v položkách objednávek. |
Kdyby SŘBD neuměl pracovat s transakcemi, mohlo by se stát, že objednávka zůstane vytvořená (kroky 2 a 3), ale zboží se neodečte (nebo naopak). Díky operaci ROLLBACK se databáze vrátila přesně do stavu, v jakém byla před krokem 1. Z pohledu databáze se tedy „nic nestalo“.

Zamykání
Databázový systém přirozeně umožňuje práci většímu počtu uživatelů najednou – databázové systémy jako například SAP HANA umožňují, aby se systémem pracovaly stovky i tisíce uživatelů ve stejný čas. V takovém případě je samozřejmě životně důležité zajistit, aby si „nelezli do zelí“. A právě k tomu slouží zamykání.
Cílem zamykání (locking) je zabránit tomu, aby se databáze dostala do nekonzistentního stavu (například dva lidé vyberou peníze ze stejného účtu v naprosto shodný čas a dostanou účet do mínusu, aniž by o tom systém věděl).
Rozlišujeme dva základní typy zámků podle toho, jak moc ostatní uživatele potřebujeme omezit:
- X-lock – exclusive (výlučný) – záznam je zcela uzamčen a číst i měnit může pouze vlastník zámku (nikdo jiný)
- S-lock – shared (sdílený) – záznam je uzamčen pro zápis (zapisovat či měnit může pouze vlastník zámku), ale čtení je povoleno (číst mohou všichni oprávnění uživatelé)

Příklady použití S-locku
- generování měsíční faktury (během generování systém čte větší množství položek; ostatní si je mohou také zobrazit, ale nikoliv měnit – to je možné až poté, co se faktura dogeneruje)
- zobrazení zůstatku účtu v bankomatu (v momentě, kdy se zůstatek načítá, nesmí proběhnout jiná transakce; ostatní mohou transakce zobrazit, ale nikoliv měnit – to je možné až poté, co se částka vypočítá a zobrazí)
Příklady použití X-locku
- změna hesla uživatele (jakmile si uživatel mění heslo v nastavení profilu, nikdo jej nesmí ani číst, ani jinak měnit – i administrátor musí počkat, dokud se nové heslo neuloží, jinak by si přečetl „poloviční“ nebo neplatná data)
- změna počtu kusů zboží na skladě (jakmile dochází k naskladnění / vyskladnění zboží, nikdo jej nesmí ani číst, ani jinak měnit – je potřeba počkat, dokud se počet neaktualizuje)
Problém deadlocku (uváznutí)
Při zamykání může nastat velmi specifická a nebezpečná situace zvaná DEADLOCK – jedná se o případ, kdy dvě (nebo více) transakcí čekají na uvolnění zdrojů, které drží ta druhá transakce. Ani jedna transakce nemůže pokračovat a čekaly by tedy do nekonečna.
Příklad deadlocku
- Transakce 1 zamkne tabulku Zákazníci a čeká na uvolnění tabulky Objednávky.
- Transakce 2 zamkne tabulku Objednávky a čeká na uvolnění tabulky Zákazníci.
- Výsledek: obě transakce čekají na sebe navzájem a neskončily by nikdy

Jak SŘBD tedy deadlock řeší?
Databázový systém musí umět tuto situaci detekovat a vyřešit:
- Detekce a Rollback: SŘBD zjistí, že došlo k cyklickému čekání. Vybere jednu transakci (oběť), tu násilně ukončí (ROLLBACK), čímž uvolní zdroje pro druhou transakci.
- Timeout (Časový limit): Nastaví se maximální doba čekání na zámek. Pokud transakce čeká příliš dlouho (např. 60 sekund), systém předpokládá problém a automaticky provede ROLLBACK.
START TRANSACTION;
Situace, kdy dvě nebo více transakce čekají na uvolnění zdrojů, které drží jiná transakce v téže skupině a žádná tudíž nemůže pokračovat.
Vlastnost databáze „všechno nebo nic“ – transakce se provede buďto celá, nebo vůbec.
Při generování měsíční faktury – ostatní mohou číst, ale nesmí měnit.
X-lock (eXclusive)
ROLLBACK
Zabránit tomu, aby se databáze dostala do nekonzistentního stavu při souběžném přístupu více uživatelů.
SAVEPOINT
S-lock (Shared)
SŘBD zjistí cyklické čekání a vybere jednu transakci a násilně ji ukončí pomocí ROLLBACK.
S-lock a X-lock (Shared, eXclusive)
Logická jednotka skládající se z jedné či několika databázových operací, které z pohledu uživatele tvoří jeden nedělitelný celek.