# Transakce ## Transakční zpracování **Ochrana integrity dat** - stav databáze - dán hodnotami objektů databáze v daném okamžiku - objektem se rozumí - tabulka, záznam, položka a spojení **Konzistentní stav databáze** - podmínky definující konzistentní stav databáze jsou definovány integritními omezeními - jednoduché deklarativní formou - složitější procedurální formou **Porušení integrity DB** - porušení integrity DB = porušení konzistentního stavu DB - příčiny - selhání technického/hw zařízení (disk) - selhání operačního systému - chyba v aplikačním programu - chybný zásah obsluhy - chybná data - příčin porušení integrity je tolik, že je těžké jim zabránit - SŘBD je tedy vybaven - mechanismem detekce nekonzistentního stavu - mechanismem zotavení **Ochrana integrity** - prostředky poskytnuté OS - kopie souboru (zpravidla na různá média) - kontrolní bod (záloha všech souborů a případné obnovení) - speciálně vyvinuté pro databázové systémy - transakce **Transakce** - posloupnost operací nad objekty databáze - z pohledu uživatele ucelená operace - je - logickou jednotkou práce - jednotkou zotavení z chyb - po dobu provádění transakce není databáze v konzistentním stavu - příklad: změna čísla čtenáře - u čtenáře ale i všech jeho výpůjček **Stavy transakce** - aktivní (A) - stav od začátku provádění - chybný (F) - v pokračování transakce nelze pokračovat - částečně potvrzený (PC) - po provedení poslední elementární operace - transakce nebyla dosud potvrzena - zrušený (AB) - po příkazu `ROLLBACK`, vrácení do původního stavu - potvrzený (C) - úspěšné doknčení a potvrzení příkazem `COMMIT` **Vlastnosti transakce** - atomicita (**A**tomicity) - buď všechny operace nebo žádná - konzistence (**C**onsistency) - DB v konzistentním stavu před i po transakci - izolovanost (**I**solation) - paralelně probíhající transakce se nijak neovlivňují - trvalost (**D**urability) - po úspěšném potvrzení transakce všechny změny v databázi nemohou být ztraceny (ani při havárii systému) **Žurnál** - základní nástroj pro ochranu transakcí - znám též jako logovací protokol - zapisují se do něj změny od posledního kontrolního bodu - obecně obsahuje - identifikaci transakce - kdo změnu provádí - kdy je změna provedena - kterého objektu se týká - novou hodnotu objektu - někdy i starou/původní hodnotu objektu **Metody používání žurnálu** - dopředné procházení (`REDO`) - po chybě se vychází z kopie uložené v kontrolním bodě - postupně se provádí změny uložené v žurnálu až do chybového okamžiku - potřebujeme jen nové hodnoty objektů - zpětné použití žurnálu (`UNDO`, `ROLLBACK`) - po chybě se vychází ze současného (nekonzistentního) stavu DB - využíváme starých hodnot v žurnálu do začátku chybné transakce - postupným zpětným odvíjením žurnálu se dojde k začátku chybné transakce **Metody ochrany transakce** - odložený zápis do databáze - tvorba žurnálu s odloženými realizacemi změn - v minulosti též **dvoufázové potvrzování** - přímý zápis do databáze - tvorba žurnálu s bezprostřední realizací změn **Odložený zápis do databáze** - transakce nesmí měnit hodnoty objektů v databázi dříve, než je částečně potvrzena - transakce nemůže být částečně potvrzená, pokud není vytvořen příslušný záznam o změnách v žurnálu - žurnál nevyžaduje staré hodnoty objektů - nevýhoda: pomalé + pokud došlo k chybě + před uložením do žurnálu + přechod ze stavu _aktivní_ do _částečně porvrzený_ + nedošlo ke změnám v databázi (zůstala v konzistentním stavu) + po částečném potvrzení transakce + přechod ze stavu _částečně potvrzený_ do stavu _potvrzený_ + všechny změny jsou uloženy v žurnálu + na žurnál bude použita metoda `REDO` **Strategie obnovení odloženého zápisu do DB** - vytvoříme seznam `REDO` - žurnál procházíme od kontrolního bodu do předu - narazíme-li na konec transakce, vložíme ji do `REDO` - transakce v seznamu `REDO` zpracujeme metodou `REDO` - nedokončené transakce řešit nemusíme, protože neprovedly žádný zápis do databáze **Přímý zápis do databáze** - změny v DB se provedou okamžitě v době potřeby před potvrzením transakce - v žurnálu je nutné uchovat staré hodnoty objektů - v případě chyby se provádí _vycouvání_ transakce použitím metody `UNDO` - výhoda: rychlé + při chybě disku, kde mám uložený žurnál, nelze použít + do žurnálu nutno zapisovat i operace čtení + novou hodnotu objektu zapsanou dosud nepotvrzenou transakcí může číst jiná transakce + při vycouvání aktuální transakce proto musí vycouvat i ty transakce, které četly nové hodnoty objektů + to může vést až k tzv. kaskádovému rušení transakcí - známý také jako dominový efekt - nejedná se o nějak častý jev **Strategie obnovení přímého zápisu do DB** - vytvoříme dva seznamy: `REDO` a `UNDO` - do seznamu `UNDO` vložíme všechny transakce z kontrolního bodu - seznam `REDO` zůstane prázdný - žurnál procházíme od kontrolního bodu do předu - narazíme-li na začátek transakce, vložíme ji do `UNDO` - narazíme-li na konec transakce, převedeme ji z `UNDO` do `REDO` - transakce zpracujeme metodou odpovídající názvu seznamu, ve kterém se nachází ## Paralelní zpracování transakcí **Moduly SŘBD pro zpracování transakcí** - z pohledu synchronizace nás ze SŘBD zajímají tyto moduly - modul řízení transakcí (RT) - transakce se na něj obracejí se žádostí o vykonání operace - modul řízení obnovy databáze (RD) - v databázi vykoná (realizuje) čtení/zápis podle požadavků plánovače - plánovač - zabezpečuje synchronizaci požadavků více transakcí v RT - požadavky zařazuje do tzv. plánů (rozvrhů) **Zadání příkladu** - ve všech příkladech budeme označovat - objekty (na disku) písmeny z konce abecedy - interní proměnné ze začátku abecedy - mějme - počáteční hodnotu `X := 10` - dvě transakce `T1` a `T2` mající shodnou činnost | T1 | T2 | | ---- | ---- | | `A := read(X)` | | | `A := A + 5` | | | `write(X, A)` | | | | `B := read(X)` | | | `B := A + 5` | | | `write(X, B)` | - je několik možných plánů, kdy někde se může čtení z disku spustit dříve, než se zapíše předchozí výsledek **Uspořádatelnost** - serializovatelnost - efekt paralelního zpracování transakcí musí být stejný, jako by byly transakce uspořádány v nějakém sériovém plánu Příklad: původní hodnota `X := 10` ```python # T1 A := read(X) A := A + 5 write(X, A) # T2 B := read(X) B := B * 3 write(X, B) ``` - plán 1 (T1, T2), X = 45 - plán 2 (T2, T1), X = 35 + paralelní běh transakcí může skončit jedním nebo druhým výsledkem ### Uzamykací protokoly **Operace `LOCK(X)`** - uzamknutí objektu X vyvolá transakce, aby ho ochránila před přístupem jiných transakcí - objekt smí být uzamčen pouze jednou transakcí - pokud chce objekt uzamknout ještě jiná transakce, je systémem pozastavena **Operace `UNLOCK(X)`** - odemknutí objektu X - objekt může odemknout jen ta transakce, která jej uzamkla - pokud na odemčení tohoto objetu čeká jiná transakce, může být opětovně spuštěna **Dvoufázový (zamykací) protokol** - lze dokázat, že uspořádatelnost plánu je zaručena, jestliže - objekt může být v každém okamžiku uzamčen pouze pro jednu transakci - jakmile transakce odemkne alespoň jeden objekt, nesmí už žádný objekt uzamknout - poznámka - nesmí uzamknout ani ten samý objekt, co odemkla (prostě nesmí žádný objekt uzamknout) - porušení dvoufázového protokolu hrozí v případě, že si sami definujete a řídíte transakce + Two-phase locking (2PL) + fáze 1: růst (expanding) + transakce smějí pouze zamykat objekty, nesmí je odemykat + fáze 2: smršťování (shrinking) + transakce smějí pouze objekty odemykat, nesmí žádný objekt uzamknout **Zamykání objektů** - databázové objekty lze zamykat ve dvou režimech - výlučný, též exklusivní režim - sdílený režim - výlučný režim - objekt je uzamčen pro operace čtení i zápis - nemůže být současně uzamčen jinou transakcí - sdílený režim - objekt je uzamčen jen pro operaci čtení - daný objekt může být současně uzamčen v režimu čtení další transakcí **Uváznutí** (deadlock) - dodržení dvoufázového protokolu ještě neznamená odstranění všech potíží - zásadní výhoda DB: transakce umí `ROLLBACK` | T1 | T2 | | --------- | --------- | | `LOCK(X)` | | | | `LOCK(Y)` | | `LOCK(Y)` | | | | `LOCK(X)` | ## Další protokoly Musíme znát nějakou další informaci o objektech databáze, např. způsob jejich uložení **Stromový uzamykací protokol** (Tree protocol) - používá zámky - pro hierarchické databáze - reprezentace tzv. grafového protokolu 1. první výlučný zámek transakce T lze použít na jakýkoliv objekt X 2. další objekt může být uzamčen transakcí T pouze když byl v T uzamčen jeho předchůdce 3. objekty mohou být odemknuty kdykoliv 4. objekt, který byl v transakci T uzamknut a odemknut nesmí být už v T následovně znovu uzamknut - všechny plány jsou uspořádatelné a nemůže dojít k uváznutí **Protokol časových značek** - místo zámků používá tzv. časové značky ČZ - předává ji systém, tvoří rostoucí posloupnost - plánovač transakcí vykonává konfliktní transakce (pracují nad stejným objektem X) v pořadí jejich ČZ - takto navržené plány jsou uspořádatelné - u každého objektu X jsou zaznamenávány největší značky - pro čtení R_ČZ(X) - pro zápis W_ČZ(X) ## Transakce v praxi **Zajištění konzistence v SŘBD Oracle** - konzistentní čtení (Multiversion Read consistency) - na úrovni příkazu (Statement-Level Read Consistency) - data získaná dotazem jsou vždy potvrzená - na úrovni transakce (Transaction-Level Read Consistency) - každý příkaz transakce vidí data nová, která byla transakcí zapsána - ostatní transakce vidí data, která byla dostupná před začátkem transakce - ke správě konzistentního čtení se využívají tzv. návratové segmenty - uloženy v tzv. návratovém tabulkovém prostoru **Nežádoucí jevy při čtení dat v transakcích** - **Špinavé čtení** (Dirty read) - též nepotvrzené čtení (Uncommited read) - příklad - transakce T1 aktualizuje vybraný záznam - transakce T2 následně přečte tuto aktualizovanou hodnotu dříve, než proběhne její potvrzení - problém nastane, když transakce T1 bude zrušena, tj. zavolá `ROLLBACK` - potom transakce T2 přečetla hodnotu, která neměla existovat + **Neopakovatelné čtení** (Non-repeatable read) - nastane, pokud čteme opakovaně stejnou hodnotu, ale v různých časech obdržíme různé hodnoty - příklad - transakce T1 přečte vybraný záznam - transakce T2 následně daný záznam aktualizuje a bude potvrzena - opětovné čtení stejného záznamu transakce T1 poskytne jiná data nebo také žádná - **Fantomové čtení** (Phantom read) - nastane, pokud při opakovaném čtení získáme nová data, která nebyla dostupná při prvním čtení - příklad - transakce T1 přečte záznamy, které vyhovují dotazu - transakce T2 generuje nový záznam, která změní výsledek dotazu transakce T1 - opětovné vyhodnocení stejného dotazu transakce T1 poskytuje data navíc **Úrovně izolace transakce dle normy** - **Serializovatelná** (serializable) - nejvyšší stupeň izolace - dovoleno vykonávat pouze uspořádatelné plány - transakce čeká, dokud záznamy uzamčené pro zápis ostatními transakcemi budou odemčeny - transakce drží zámky buď pro čtení anebo pro zápis pro rozsah záznamů, které chce buď číst anebo ovlivnit zápisem - rozsahem záznamů se rozumí výsledek selekce transakce - pokud jiná transakce vloží/aktualizuje/smaže záznam, který do daného rozsahu zapadá, nebude jí zápis povolen - transakce uvolňuje všechny zámky po jejím potvrzení nebo odvolání + **Opakovatelné čtení** (repeatable read) - transakce čeká, dokud záznamy uzamčené pro zápis ostatními transakcemi budou odemčeny - transakce drží - zámky pro čtení pro záznamy, které chce číst - zámky pro zápis pro záznamy, které chce vkládat/aktualizovat/mazat - jiná transakce může vložit/aktualizovat ty záznamy, které spadají do rozsahu záznamů uzamčených pro čtení - transakce uvolňuje všechny zámky po jejím potvrzení nebo odvolání - **Potvrzené čtení** (read commited) - transakce čeká, dokud záznamy uzamčené pro zápis ostatními transakcemi budou odemčeny - transakce drží - zámek pro čtení pro aktuálně čtený záznam - zámek pro zápis záznamu, který chce aktualizovat/mazat - transakce uvolňuje - zámek pro čtení po přečtení aktuálního záznamu - zámky pro zápis po potvrzení nebo odvolání transakce + **Nepotvrzené čtení** (read uncommited) - nejnižší stupeň izolace - transakce není izolovaná od ostatních transakcí - obvykle je tato úroveň použita u transakcí v režimu čtení - čte i nepotvrzené záznamy jiných transakcí | | špinavé čtení | neopakovatelné čtení | fantomové čtení | | ----------------------- | -------------- | -------------------- | --------------- | | serializovatelná úroúveň | nevyskytuje se | nevyskytuje se | nevyskytuje se | | opakované čtení | nevyskytuje se | nevyskytuje se | VYSKYTUJE SE | | potvrzené čtení | nevyskytuje se | VYSKYTUJE SE | VYSKYTUJE SE | | nepotvrzené čtení | VYSKYTUJE SE | VYSKYTUJE SE | VYSKYTUJE SE | **Izolace transakce v SŘBD Oracle** - Read Commited Isolation Level - výchozí úroveň - transakce vidí data dostupná před začátkem transakce - dovoluje jevy neopakovatelné a fantomové čtení - trpí efektem ztráty aktualizace dat (lost update) - Serializable Isolation Level - transakce vidí potvrzené změny v čase začátku transakce a změny provedené v transakci - brání všem nežádoucím jevům čtení, netrpí efektem ztráty aktualizace dat - Read-Only Isolation Level - podobné jako předchozí úroveň - transakce nemají přístup k datům, které modifikují jiné transakce **Ztráta aktualizace** - nastane, pokud souběžné transakce modifikují hodnotu stejného záznamu - zůstane zapsaná až poslední změna, předchozí se ztratí - příklad - transakce T1 modifikuje hodnotu konkrétního záznamu - transakce T2 také později chce modifikovat hodnotu stejného záznamu, ale je pozastavena - transakce T1 bude poté potvrzena, následně dojde k modifikaci dat transakce T2 - transakce T2 bude potvrzena **Nastavení úrovně izolace** - na úrovni transakce ```sql SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET TRANSACTION ISOLATION LEVEL READONLY; ``` - na úrovni aktuálního spojení ```sql ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED; ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE; ALTER SESSION SET ISOLATION_LEVEL READONLY; ```