Další žádanou vymožeností, která přibyla do verze 5 databázového
stroje MySQL jsou triggery. Dnes se podíváme na to, co to přesně
triggery jsou a k čemu jsou v databázovém světě dobré. Bude to spíše
teoretické povídání s tím, že věci specifické pro MySQL budou
soustředěny do následujícího článku.
Triggery
Především - existuje krásné české slovo, jímž se dá přeložit
anglické trigger - a to je spoušť. Moc se ale neujalo. Možná
proto, že zní tak nepořádně. Představte si třeba větu "po mojí úpravě
kódu zůstala v databázi pěkná spoušť". Protože tohle by asi většina
uživatelů slyšet nechtěla, budu používat spíš původní, anglické slovo
trigger.
Suchá definice pak praví, že trigger je uložená procedura, která se
spouští v souvislosti s provedením nějakého akčního dotazu na tabulce.
Pokud tuto definici trochu rozpitváme, dostaneme z ní následující
informace:
- Trigger je "uložená procedura", to znamená, že uvnitř triggeru
lze provádět většinu věcí, které umí uložené procedury. V triggeru lze
mít například smyčku, podmínku, lokální proměnnou, matematický výpočet
a podobně.
- Spouští se "v souvislosti" s akčním dotazem. To v praxi znamená,
že se trigger může spustit buď předtím, než je úprava dat provedena,
nebo poté, co jsou změny v datech zapsány do databáze. Některé databáze
umožňují pouze triggery před uložením dat, ale většina (včetně MySQL)
má k dispozici oba typy.
- "Akční dotaz" znamená, že trigger lze spustit při vkládání dat,
při jejich aktualizaci nebo při odstraňování dat z databáze. Rovněž z
toho vyplývá, že trigger nelze v žádném případě spustit příkazem
SELECT.
- "na tabulce" - každý trigger patří právě jedné tabulce. Ačkoli
samozřejmě může existovat tabulka bez triggeru, není možné, aby
existoval trigger nezávisle na tabulce. V některých DBMS může být více
triggerů stejného typu na jedné tabulce a lze dokonce určit pořadí, v
němž budou spuštěny. V MySQL však některé z těchto věcí nejsou možné.
Čím se liší od uložených procedur
Triggery mají sice stejnou syntaxi jako uložené procedury, přesto se
od nich v lecčems liší. Tak především triggerům není možné předávat
žádné vstupní parametry. To znamená, že trigger nemá žádné informace o
tom, jak by měl být prováděn, které by se daly "zvenčí" přepínat za
chodu. Triggery navíc narozdíl od uložených procedur nemohou vracet
sadu záznamů. A navíc, databázové systémy mívají některá omezení a
příkazy, které se v triggerech nesmějí objevit. Pro MySQL platí, že se
v triggeru nesmí objevit přinejmenším tyto příkazy:
- Příkazy ALTER (ALTER TABLE, ALTER DATABASE a tak dále)
- Příkazy pro řízení transakcí (START TRANSACTION, ROLLBACK, COMMIT)
- Volání procedur (CALL)
- Příkazy pro nastavování práv (GRANT, REVOKE)
- a některé další příkazy
Na druhou stranu mají triggery oproti uloženým procedurám něco
navíc; mají totiž "vevnitř" přístup k datům, která se právě mění. To
například znamená, že trigger, který se spouští před aktualizací nějaké
tabulky má přístup k hodnotám těch řádků, které se snažíme změnit. Také
to znamená, že v triggeru můžete provést nějaké rozhodnutí v závislosti
na datech, která má tento trigger změnit.
Jak se používají
Triggery se v tabulkách používají z několika důvodů. Ty mohou
souviset s konzistencí dat, s jejich správou a údržbou nebo s tím, jak
a kdy bude databáze komunikovat se svým okolím. Abyste měli určitou
představu, nastíním některé typičtější scénáře:
- Konzistence dat: Trigger může provést výpočet a na základě toho
povolit nebo nepovolit změnu dat v databázi. Například v tabulce
skladových zásob může být trigger, který zakáže vyskladnit zboží v
případě, že bychom se tím dostali do záporného stavu zboží. Trigger
může zakázat smazání zákazníka z databáze v případě, kdy má u nás
nějaký dluh a podobně.
- Protokolování změn: Trigger může evidovat kdo, kdy a jak měnil
data. Lze tak dohledat pracovníka, který zadal špatné údaje nebo
zjistit, v kolik hodin došlo k navstupování včerejší uzávěrky.
- Verzování dat: Díky triggerům lze snadno naprogramovat aplikaci
tak, aby jedna tabulka udržovala historii změn tabulky jiné. To lze s
úspěchem použít třeba jako bezpečnostní mechanismus. (Pouze nám tím
databáze dost naroste).
- Zasílání zpráv světu: Trigger může spustit nějaký externí program
nebo proces. Poněkud otřepaný příklad praví, že při změně ceny akcií
rozešle databáze e-maily obchodníkům; jistě si ale dokážete představit
i jiné využití.
Typický scénář použití triggerů je tedy takový:
- Databáze zachytí požadavek na změnu dat - dejme tomu na
aktualizaci dat v tabulce.
- DMBS zjistí, zda je pro tuto tabulku definován trigger, který se
má provést před aktualizací záznamů. Pokud ano, provede jej.
- Jestliže trigger aktualizaci nezrušil, zapíší se data do tabulky.
- DMBS zjistí, zda je pro tuto tabulku definován trigger, který se
má provést po aktualizací záznamů. Pokud ano, provede jej.
- Dokončeno. Systémové prostředky použité pro zápis dat jsou
vráceny systému a čeká se na další požadavek.
Aplikační logika v databázi
Poněkud kontroverzním tématem je použití triggerů jako centrálního
bodu pro vytvoření či správu aplikační logiky. Zastánci tohoto přístupu
tvrdí, že pomocí triggerů se v dnešní době ná naprogramovat prakticky
cokoliv a výsledek pak mohou používat všechny aplikace sdílející danou
databázi; odpůrci zase tvrdí, že databáze by měla sloužit jako úložiště
dat a pro správu aplikační logiky by měly sloužit aplikační servery.
Jak už to bývá, pravda je někde uprostřed. O tom, kolik toho budou
zajišťovat triggery budete muset nakonec rozhodnout ve svých aplikacích
sami.
Na co dát pozor
Přestože triggery jsou ve spoustě situací velmi přínosné, měli byste
vědět, že jsou s nimi spojena určitá úskalí. Především - každý trigger
zabere nějakou dobu. Pokud budete mít triggerů více a/nebo pokud budou
provádět časově dlouhé operace, můžete si snížit dobu odezvy databáze
na akční dotazy. Rovněž triggery se obtížně ladí. Klasický akční dotaz
změní data a skončí; trigger může data modifikovat, uložit jinam nebo
operaci zakázat. Díky tomu bývá občas velmi obtížné zjistit, co se
vlastně v databázi děje - a to je tím palčivější, čím více triggerů
máte a čím složitější akce provádějí.