Kolízie pri ukladaní do databázy (transakcie, zamykanie, object version)
Za určitých okolností může docházet k tzv. kolizím při ukládání dat. Kolize mohou mít celou řadu příčin. Např. pokud se dva uživatelé současně pokusí opravit týž záznam, nebo pokud se uživatel pokusí opravit záznam v neobčerstveném číselníku či neobčerstvené dokladové agendě, přičemž příslušný záznam byl mezitím opraven např. z agendy otevřené v jiném okně aplikace či jiným uživatelem v síti apod. Rôzne typy kolízií sa riešia rôzne. Zde se pokusíme objasnit, jak může ke kolizím dojít a jakým způsobem je systém řeší.

Přístup k problematice řešení kolizí při ukládání dat prošel v systému ABRA Gen určitým historickým vývojem.

V síťové verzi systému ABRA Gold (předchůdce ABRA Gen) se používala technologie zamykání záznamů, která vzniku kolizí zabraňovala - každý záznam mohl v jednom okamžiku měnit pouze jeden uživatel. Na druhou stranu byl tento přístup pro uživatele poměrně omezující - po celou dobu opravy jedním uživatelem byl záznam pro ostatní uživatele uzamčen a museli čekat na jeho uvolnění. Tento přístup se označuje jako pesimistický. Objasníme na jednoduchom príklade:
Príklad 1: Majme užívateľov Nováka a Kováča, pracujúcich v sieťovej inštalácii ABRA Gold. Ďalej nadefinované stredisko 100 s názvom Obchod a ulicou Dlhá 50. Užívateľ Novák chce vykonať opravu strediska 100, konkrétne jeho názov, a užívateľ Bláha chce z nejakého dôvodu tiež opraviť to isté stredisko 100, konkrétne meno ulice. Novák zaháji opravu strediska 100. V tom momente dôjde k zamknutiu záznamu strediska v databáze. Keď chce Kováč zahájiť opravu, systém oznámi, že to nie je možné, pretože záznam je uzamknutý a opravu nepovolí. Bláha musí počkat, až Novák svou opravu ukončí a záznam uvolní.

V systému ABRA Gx byl zaveden jiný přístup, který byl později převzat i do ABRA Gen. Jak bylo uvedeno v kapitole o technologii zpracování dat, jedná se o databázový klient/server systém, pracující na principu tzv. transakcí:
- je zahájena nějaká transakce s cílem provést požadovanou akci, např. uložit změny v záznamu (start transakce)
- následně transakce probíhá
- pokud se celou transakci podaří provést, je úspěšně ukončena, neboli potvrzena (commit transakce)
- pokud se celou transakci provést nepodaří (dojde k nějaké kolizi, např. nelze uložit data daného záznamu, jelikož byl změněn současně v rámci jiné transakce, či je blokován jinou transakcí), není transakce potvrzena a vše se vrátí zpět do stavu před jejím zahájením (rollback transakce)
V takovýchto systémech se většinou nepoužívá zahajování transakcí ihned při zahájení manipulace se záznamem, např. při vyvolání funkce Opravit (protože oprava záznamu by teoreticky mohla trvat i velmi dlouho, transakce by musela běžet po celou dobu provádění změn a podpora dlouho trvajících transakcí není u SQL databází obvyklá).
V ABRA Gen sa preto transakcia vo väčšine prípadov zaháji až v okamihu ukladania. Uživatelsky to např. znamená, že je možné zahájit stejnou operaci se stejným záznamem a teprve při ukládání se kontrolují a řeší případné kolize. Tato technologie sice vzniku kolizí nepředchází, ale na druhou stranu uživatele nijak neomezuje, a proto se někdy označuje jako optimistický přístup. Vzniklou kolizi objasníme na stejném příkladu:
Príklad 2: Užívateľ Novák aj Kováč zaháji opravu strediska 100, Novák zmení názov strediska na Obchod celkom (ulicu nemení) a Kováč zmení ulicu na Krátku 475 (názov strediska nemení). Novák záznam uloží. Akce uložení vyvolá zahájení a úspěšné potvrzení příslušné transakce, stav v databázi tedy je "středisko 100, Obchod celkem, Dlouhá 50". Poté chce uložit své změny Bláha. Zaháji sa transakcia. Systém ale zjistí, že záznam střediska byl (mezitím, co Bláha opravoval ulici) změněn a nahlásí kolizi (nemůže sám o sobě rozhodnout, jak pokračovat, zda ponechat změnu názvu provedenou Novákem, anebo data, která má Bláha, tj. původní název a novou ulici. Systém transakciu zruší, akcia uloženia neprebehne.
Riešenia takýchto kolízií sú rôzne a závisia od ich konkrétneho typu.
Simulácia pesimistického zamykania:
K situacím, kdy dva uživatelé začali v jeden okamžik opravovat tentýž záznam, docházelo v některých provozech často. Při výše popsaném optimistickém přístupu nastávaly kolize, tedy jeden z uživatelů nemohl své údaje uložit, o provedené změny přišel a musel je zadat znovu (podrobněji viz dále Kolize při změně ObjectVersion). To bylo nepříjemné zejména v případech déletrvajících editací rozsáhlých záznamů (např. několikařádkových dokladů). Aby se mohlo v těchto případech kolizím předcházet, byla do systému přidána možnost simulace pesimistického zamykání.
Simulace pesimistického zamykání se aktivuje pomocí parametru PessimisticEditLock, který musí být uveden v souboru nexus.cfg v sekci [
Příklad hlášení při pokusu o souběžnou editaci téhož záznamu s aktivovanou simulací pesimistického zamykání.

Každý z uvedených způsobů má své výhody i nevýhody. V současné době je využívána kombinace různých přístupů ve snaze maximalizovat efektivitu práce při souběžném používání systému větším množstvím uživatelů, konkrétně:
- na úrovni business objektů byl zachován optimistický přístup
- na úrovni uživatelského rozhraní je používána simulace pesimistického zamykání
Oproti dosavadnímu stavu byla nicméně zavedena celá řada vylepšení a změn. V současné době platí následující:
-
Simulace pesimistického zamykání je stále záležitostí uživatelského rozhraní systému (nejedná se o vlastnost business objektů), nicméně je možné s ní pracovat i ve skriptování a Web API.
Viz související FAQ Jak pomocí skriptování pracovat se zamykáním záznamů?
- Vytváření zámků je vázáno pouze na používání funkce Opravit v dokladových a číselníkových agendách. Není tedy implementováno v agendách jako jsou Firemné údaje, Nastavenie parametrov miezd, Nastavenie kompletizácie, Definícia kľúčov, Nastavenie gastrovýroby apod.
-
Nejsou kontrolovány ani změny záznamů prováděné jiným způsobem, např.:
- Aktivity - funkce Předat
- Zákazky, Obchodné prípady, Projekty - funkce Uzavřít / Zrušit uzavření
- Odoslaná pošta (PO) - funkce Uzávěrka
- a pod.
-
Ke konfliktům může stále docházet při ukládání následných dokladů. Možné příčiny a vysvětlení:
- Při použití funkce Vytvořit se nevytvoří žádný nový zámek.
- Na nově vytvářeném dokladu se zámek nevytvoří proto, že se jedná o nový záznam a nikoli o opravu. Toto ničemu nevadí, protože ostatní uživatelé vytvářený následný doklad nevidí, dokud ho uživatel neuloží.
- Zámek se ale nevytvoří ani na zdrojovém dokladu, protože vytváření zámků je vázáno pouze na funkci Opravit (nikoli Vytvořit). Toto vadit potenciálně může, protože úspěšné uložení následného dokladu je podmíněno vytvořením vazby, kterou je zapotřebí zapsat do zdrojového dokladu. Pokud zdrojový doklad začne souběžně editovat někdo další, dojde později ke konfliktu. O existenci konfliktu se však uživatel dozví až při pokusu o uložení, nikoli při zahájení vytváření následného dokladu.
- Nekontroluje se existence případného zámku na zdrojovém dokladu při používání funkcí Vytvořit nebo Opravit.
- Při použití funkce Vytvořit se neprovádí kontrola na existenci zámku na zdrojovém dokladu, tj. neověřuje se, zda bude možné při ukládání následného dokladu vytvořit mezi následným a zdrojovým dokladem vazbu (bez které není uložení následného dokladu možné). Uživatel vytvářející následný doklad se o existenci konfliktu opět dozví až při pokusu o uložení.
- Kontrola se neprovádí ani při použití funkce Opravit na následném dokladu, který byl ze zdrojového vytvořen v minulosti - zámky a kontroly jsou pouze jednoúrovňové. Pokud byl například z objednávky přijaté vytvořený dodací list a uživatel A začne dodací list opravovat, automaticky vytvořený zámek zamezí pouze zahájení souběžné editace tohoto dodacího listu, možnost editace zdrojové objednávky nijak neomezuje. Pokud tedy mezitím někdo opraví zdrojovou objednávku, dojde ke konfliktu a uživateli A se nepodaří dodací list uložit.
Ke konfliktům může docházet v obou směrech - neúspěchem může skončit pokus o uložení zdrojového i následného dokladu. Záleží na tom, ke kterým dokladům se v průběhu editace vytvořily zámky, které jsou v okamžiku ukládání stále platné.
Jednu z možných konfliktních situací demonstruje následující příklad.
Príklad...
Uživatel A se rozhodne vytvořit Dodací list z objednávky přijaté. V agendě Objednávky prijaté (OP) použije funkci Vytvořit s volbou Dodací list, vyplní požadované údaje v průvodci a v novém okně se mu otevře předvyplněný dodací list.
Zatímco uživatel A předvyplněný dodací list upravuje, uživatel B si otevře stejnou objednávku k editaci (použije funkci Opravit). Uživatel A stále upravuje dodací list.
Uživatel A dokončí úpravy dodacího listu a pokusí se ho uložit. Uložení se mu však nezdaří, protože v rámci transakce je zapotřebí provést změnu zdrojové objednávky přijaté (aktualizovat na ní informaci o čerpání). Uživatel A je o konfliktu informován a požadované změny musí provést znovu (znovu vytvořit dodací list).
Uložení DL se nezdařilo kvůli souběžné editaci zdrojové objednávky.
Pokud by uživatel B editovanou objednávku mezitím uložil (dříve než by se uživatel A pokusil uložit vytvářený následný dodací list), uložení DL by se uživateli A stejně nezdařilo, protože uložení objednávky uživatelem B způsobilo zvýšení její ObjectVersion.
Uložení DL se nezdařilo kvůli neaktuální verzi zdrojového objektu. - Při použití funkce Vytvořit se nevytvoří žádný nový zámek.
- Nekontroluje se případné smazání uzamčeného dokladu provedené jiným uživatelem.
- Kontrola (nikoli vytváření zámků) se vztahuje i na hromadné opravy. Tj. pokud byl rozeditován záznam a někdo se pokusil použít hromadnou opravu nebo hromadnou opravu uživatelských položek téhož záznamu, byl na uzamčení záznamu upozorněn a daný záznam nebyl hromadnou opravou nijak změněn.
- Pesimistické zamykání je (na rozdíl od situace do verze 18.01 / 18.03) ve výchozím nastavení aktivní. V případě potřeby je možné jej deaktivovat (nastavit PessimisticEditLock=0 v sekci [Client] v souboru Nexus.cfg).
-
Okno informující o probíhající editaci záznamu nově obsahuje identifikaci uživatele, který opravu zamčeného záznamu provádí (takže se uživatelé mohou snáze dohodnout mezi sebou).
Okno informující o probíhající editaci záznamu
Zobrazení detailů po stisku tlačítka Více v předchozím okně
- Zámek se sice vytváří na úrovni uživatelského rozhraní, ale jeho existence je kontrolována na úrovni business objektů, tj. pokud zámek vznikne v souvislosti s použitím funkce Opravit v aplikaci ABRA Gen, po dobu trvání zámku není možné záznam přepsat ani jinými způsoby (skriptování, Web API, OLE).
- Doba trvání zámku (timeout) může být (ve výchozím nastavení je) časově omezena:
- výchozí nastavení je 10 minut, tuto hodnotu je možné změnit nastavením parametru BusinessObjectEditLockTimeOut v sekci [Client] v souboru Nexus.cfg. Hodnota se zadává v milisekundách (BusinessObjectEditLockTimeOut=900000 znamená vytvoření zámku s časovou platností 15 minut, BusinessObjectEditLockTimeOut=-1 znamená časově neomezený zámek).
hodnota BusinessObjectEditLockTimeOut nastavená v souboru Nexus.cfg je platná i pro skriptování a Web API (pokud se rozhodnete zámky vytvářet i prostřednictvím těchto rozhraní)
-
Je k dispozici speciální privilegium Opravovat záznamy, které již opravuje jiný uživatel umožňující oprávněným uživatelům převzetí editačního zámku (stejné privilegium má k dispozici také Supervisor)
Příklad hlášení při pokusu o souběžnou editaci téhož záznamu s aktivovanou simulací pesimistického zamykání s možností převzetí zámku (přihlášený uživatel má k dispozici privilegium Opravovat záznamy, které již opravuje jiný uživatel).
-
Mechanismus simulace pesimistického zamykání je zohledňován také při oceňování skladových pohybů (spouštěného z agendy Uzávierka skladu i v rámci selektivního oceňování).
- Oceňování přeskakuje doklady, které se aktuálně opravují (existuje k nim platný editační zámek).
-
Oceňování vytváří krátkodobé zámky na aktuálně přeceňované doklady, aby se zabránilo pokusům o jejich souběžnou editaci jinými uživateli.
Řádky jsou aktualizovány po dávkách a doba trvání těchto zámků odpovídá době, za kterou se přecení jedna dávka, momentálně 100 řádků.

Princíp kontroly, či došlo ku kolízii
ABRA Gen si pri každom zázname v databáze (napr. záznam strediska), pamätá jednak jeho interný identifikátor ( "ID") ako aj číslo verzie tohto záznamu ( tzv. "ObjectVersion", budeme ho označovať "OV"). Ak nastane zmena záznamu, systém v databáze automaticky zvýši číslo verzie. Podľa tohto čísla sa dá potom rozpoznať, či bol objekt zmenený alebo nie.
Ku kolíziám teda môže dôjsť:
- pri chode v sieťovej inštalácii
- pri chode v dvoch oknách
- ale tiež pri chode v jednom okne pri otvorení rovnakej agendy viackrát
Objasníme na príklade:
Príklad 3: Majme otvorenú agendu faktúr vydaných v dvoch oknách. V oboch prípadoch v záložke Obmedzenie vykonáme dopyt a načítame faktúru FV-100. Táto faktúra nech má ID=ABC345 a OV=1 (v skutočnosti vyzerá inak). V prvom okne opravíme faktúru a uložíme. V tom momente sa zvýši číslo verzie, teda OV=2. V druhom okne opravujeme tú istú faktúru a uložíme. Systém porovnaním verzií zistí, že sa pokúšame uložiť "starší" záznam s OV=1, ktorý bol medzitým zmenený. Nahlási kolíziu.
Vznik takejto kolízie môžeme objasniť aj na nasledujúcej zjednodušenej schéme. Modrá farba znázorňuje stav dát dvoch súčasne pracujúcich užívateľov, červená stav v databáze. Písmená S/C/R demonštrujú S=štart, C=commit a R=rollback transakcie. V databáze nech je záznam s ObjectVersion OV=1. Užívateľ 1 zaháji operáciu oprava záznamu. Zaháji a ukončí sa teda transakcia, v rámci ktorej sa načítajú dáta z databázy (select), záznam má OV=1. Užívateľ 1 potom vykonáva požadované zmeny. Medzitým Užívateľ 2 zaháji opravu toho istého záznamu (čo môže, pretože daný záznam nie je prvým užívateľom nijako uzamknutý, tzn. aj jemu prebehne v rámci krátkej transakcie select z databázy, záznam má stále OV=1. Potom Užívateľ 1 vyvolá uloženie svojich opráv do databázy. Zaháji sa pre neho transakcia, v rámci ktorej prebehne uloženie dát (update) a ktorá prebehne úspešne. Po jej potvrdení bude mať záznam v databáze OV=2. Ak potom druhý užívateľ vyvolá uloženie svojich opráv, tiež sa mu zaháji transakcia na uloženie dát do databázy (update), ale skončí neúspešne, pretože sa medzitým zmenil ObjectVersion. Užívateľovi 2 prebehne nový select z databázy (občerstvenie dát), tzn. bude mať OV=2 a až potom bude znovu môcť zadať svoje zmeny a záznam uložiť (záznam tak získa OV=3 atď.).
Zjednodušený schématický náčrt průběhu transakcí dvou současně pracujících uživatelů.Transakce 1, 2 a 3 proběhly úspěšně (naznačeno barevnou výplní) a byly potvrzeny (commit). Transakcia 4 neprebehla úspešne a prebehol rollback.
Kolizím tohoto typu lze většinou předcházet průběžným prováděním Občerstvování! Pre editáciu záznamu navyše platí, že pred zahájením editácie si systém občerství automaticky! Tzn. pri zahájení editácie systém zistí, či nedošlo k zmene ObjectVersion záznamu, ktorý chceme editovať (čo mohlo nastať napr. tak, že iný užívateľ na sieti daný záznam zmenil a uložil, ale aktuálny užívateľ si od tej doby ešte nevykonal občerstvenie). Ak bol záznam zmenený, tak zobrazí informačné hlásenie, daný záznam automaticky občerství a až potom ho ponúkne na editáciu v editačnom režime.
Prípady vzniku kolízií sa vďaka tomu minimalizujú, no i napriek tomu k nim môže dôjsť. Prípadom, keď dvaja užívatelia rozeditujú jeden a ten istý záznam, je možné brániť simuláciou pesimistického zamykania, viď vyššie.
Väčšina kolízií tohto typu vyžaduje interakciu užívateľa. Tj. pokud dojde při ukládání ke kolizi, jelikož záznam byl změněn jiným uživatelem nebo i týmž uživatelem z jiné spuštěné úlohy ABRA Gen případně z agendy spuštěné v samostatném okně apod. a neproběhlo občerstvení, program uživatele na tuto skutečnost upozorní informačním hlášením, ve kterém případně uživateli oznámí, že z databáze byla načtena nová data (aktuální stav z databáze) a uživatel musí své změny zadat a uložit znovu.
Příklad hlášení při pokusu o uložení dokladu, který byl mezitím změněn jiným uživatelem.
Špeciálne ošetrené situácie - No v systéme sú aj prípady, keď sú takéto situácie špeciálne ošetrené, napr. pri pokuse dvoch užívateľov súčasne vykonať pohyb na tej istej čiastkovej skladovej karte (napr. obidvaja vystavujú a ukladajú dodací list s danou kartou). Na čiastkovej karte sa zaznamenáva aktuálny počet, takže po uložení prvého DL sa o. i. zmení ObjectVersion čiastkovej karty, teda druhému užívateľovi by pokus o uloženie podľa vyššie uvedenej schémy zlyhal. V tomto prípade sa systém sám vzápätí znovu pokúsi o uloženie (tzn. zjednodušene povedané: "zapamätá si" požadovanú zmenu (zmenu počtu), uskutoční select aktuálneho stavu z databázy (tzn. s OV=2), "zapíše" sám "zapamätanú" zmenu (tzn. jeho OV bude 3) a znovu sa pokúsi o uloženie (update). Ak bude pokus úspešný, transakcia s update sa ukončí a záznam čiastkovej karty bude mať aj v databáze OV=3 (takže aj druhý užívateľ bude môcť následne uložiť svoj dodací list). Tento proces prebieha na pozadí bez interakcie užívateľa (ani keď nie je zapnutá simulácia pesimistického zamykania), no len určitú definovanú dobu (cca 1 minúta). Ak sa počas tohto intervalu nepodarí uložiť (iní užívatelia s danou čiastkovou kartou neustále pracujú), systém pokusy ukončí a užívateľovi oznámi neúspešný pokus o uloženie dodacieho listu.
Zjednodušený schematický náčrt priebehu transakcií a pokusu systému zmeny užívateľa 2 uložiť, aj keď sa kvôli zásahu iného užívateľa medzitým zmenil OV záznamu v databáze (nadväzuje na predošlú schému, viď vyššie). Transakcia 4 neprebehla úspešne (viď predošlú schému). Nasleduje časový interval, v ktorom sa systém opakovane pokúsi o uloženie, tzn. načíta aktuálny stav, zaznamená zmenu a pokúsi sa uložiť (transakcie 5 a 6).

Kolízie môžu pri pokuse o uloženie nastať nielen v prípade, že bol súčasne zmenený ten istý záznam (súčasná zmena ObjectVersion), ako bolo povedané vyššie, ale aj v prípade, že sa pokúšame uložiť záznam s odkazom na iný záznam aktuálne "držaný" nejakou inou transakciou.
Ako vyplýva zo schematických obrázkov vyššie, väčšina transakcií uskutočňovaných v ABRA Gen je veľmi krátka, a pravdepodobnosť vzniku takýchto kolízií je preto u nich veľmi malá. No v systéme existujú aj prípady, keď akcia prebieha v rámci jednej dlhšie trvajúcej transakcie (uzávierka skladu, zálohovanie dát a pod.).
Ak sa v rámci nejakej dlhotrvajúcej transakcie pracuje s nejakým objektom, a užívateľ sa medzitým pokúsi uložiť záznam, ktorý na tento objekt odkazuje, pokus o uloženie zlyhá.
Príkladom môže byť práve uzávierka skladu, ktorá mení objekt sklad. Pretože však trvá dlho, objekt sklad je dlhšiu dobu nedostupný na použitie z následných transakcií. (Databáza nemôže povoliť uloženie záznamu odkazujúceho sa na takýto objekt, keďže predchádzajúca transakcia ho môže napríklad aj zmazať alebo zmeniť jeho interný identifikátor, pomocou ktorého sa odkaz realizuje a pod., takže pri pokuse o uloženie databáza čaká a v prípade, že sa v rámci určitého časového intervalu nedočká, oznámi chybu.):
Zjednodušený schematický náčrt pokusu o uloženie zmien s odkazom na objekt sklad "držaný" transakciou skladová uzávierka. Transakcia 3 neprebehne úspešne, hoci sa samotný ObjectVersion objektu sklad počas zmien uskutočnených užívateľom 2 nezmenil a je stále 2.
Popsaný problém se týká pouze uzávěrek (k datu a za období). Při oceňování skladových pohybů se aktuálně editované doklady přeskakují.

Transakcie sa "zjednodušene povedané" ukladajú po ukončení akcie v poradí, v ktorom došlo k ich zahájeniu (myslia sa transakcie zahájené v danom "connection" na databázu). Pričom ak jedna transakcia nie je ukončená, nie je možné uložiť ani nasledujúcu. Preto, keď prebieha nejaká transakcia, nie je možné prepnúť sa v rámci danej spustenej úlohy ABRA Gen do inej agendy (a to ani otvorenej v inom samostatnom okne, aj keď by šlo o iné samostatné "connection" na databázu), aby v rámci danej spustenej úlohy ABRA Gen nedochádzalo zbytočne ku kolíziám (ak by z nejakého dôvodu po ukončení napr. akcie uzávierky nebola ukončená transakcia uzávierky, nebolo by možno uložiť ani prípadné transakcie, ktoré by ste uskutočnili až potom).
V priebehu dlho trvajúcich transakcií môže v systéme dochádzať k zmenám len vtedy, ak systém prevádzkujete sieťovo a zmenu vykonávate z inej spustenej úlohy ABRA Gen.
Keď spustíte nejakú časovo náročnú akciu a súčasne chcete pracovať v inej agende, musíte si požadovanú agendu spustiť v rámci druhej spustenej úlohy ABRA Gen (sieťovo).
Spomenieme tu ešte prípad zálohovania, ktoré je jednou z dlho trvajúcich transakcií. Pri zálohovaní platí, že do zálohy sa zahrnú LEN tie dáta, ktorá sa obstarali v okamihu zahájenia transakcie zálohovania. Takže, ak by ste počas zálohovania napr. opravili nejaký doklad, vystavili nový a pod., danú zmena alebo nový doklad záloha obsahovať nebude! A to ani v prípade, ak by ste túto uskutočnili ešte skôr, ako príde "na rad" zálohovanie tabuľky databázy, v ktorej daná zmena nastala!