Nikdy nevíš, kdy to přijde
Zobrazit menu   MENU

21. Triggery

Triggery (česky vetšinou spouště) jsou velmi podobné uloženým procedurám, uvnitř lze používat víceméně stejné příkazy. V některých věcech se ale liší. Tou nejzásadnější je, že uložené procedury spouštíme my, nebo naše aplikace. Triggery jsou spouštěny automaticky jako reakce jako reakce na nějakou změnu v databázi. Takovou změnou může být vykonání příkazu INSERT, UPDATE nebo DELETE.

Další změnou oproti procedurám je, že nepřijímají žádné parametry a nemohou vracet žádné záznamy. Každý trigger se váže ke konkrétní tabulce, jejíž změny "hlídá". Trigger může být spuštěn ještě před samotnou akcí (a pracovat s daty v okamžiku před změnou), nebo až po jejím provedení.

Pokud v aplikaci využíváte příkaz TRUNCATE k vyprázdnění tabulky, nespoléhejte se na triggery. Trigger spuštěný při mazání je skutečně navázán pouze na DELETE a TRUNCATE ho nespustí.


K čemu je něco takového dobré? Snadno takto můžeme hlídat konzistenci dat (nepovolit za určitých podmínek některé operace), přenést na databázi určitou logiku aplikace, zálohovat si údaje, nebo například předpočítávat hodnoty jako výkonovou optimalizaci.

Právě tento poslední příklad si vyzkoušíme. Máme systém kde jsou uloženy články a komentáře k nim. V naší aplikaci ve výpisech článků vypisujeme u každého i počet komentářů. Můžeme se buď při vypisování každého článku dotazovat databáze na počet článků, nebo si v tabulce clanky vytvoříme sloupec, kde bude předpočítaný vždy aktuální počet komentářů. V takovém případě nebude u každého článku ve výpisu nutný nový dotaz nebo poddotaz.

K takovému předpočítání jsou triggery ideální, pokud bude vložen nový komentář, nebo by některý byl smazán, ihned hodnotu přepočítají a můžeme se tak spolehnout že bude vždy aktuální a správná. Nejdříve si vytvoříme tabulky a vložíme data:

CREATE TABLE `clanky` (
`clanek_id` int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`nazev` varchar(255) COLLATE utf8_czech_ci NOT NULL,
`text` text COLLATE utf8_czech_ci NOT NULL,
`pocet_komentaru` int(10) NOT NULL
);

CREATE TABLE `komentare` (
`komentar_id` int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`autor` varchar(100) COLLATE utf8_czech_ci NOT NULL,
`text` text COLLATE utf8_czech_ci NOT NULL,
`clanek_id` int(10) NOT NULL
);

INSERT INTO `clanky` (`clanek_id`, `nazev`, `text`, `pocet_komentaru`) VALUES
(1, 'Clanek prvni', 'Text prvniho clanku', 2),
(2, 'Clanek druhy', 'Text druheho clanku', 0);

INSERT INTO `komentare` (`komentar_id`, `autor`, `text`, `clanek_id`) VALUES
(1, 'Petr', 'Text prvniho komentare', 1),
(2, 'Adam', 'Text druheho komentare', 1);


Nyní si vytvoříme trigger, který po vložení nového komentáře aktualizuje v tabulce clanky sloupec pocet komentaru. Začínáme klíčovými slovy CREATE TRIGGER a poté v apostrofech jeho název. Následujete definice kdy se má spustit, možnosti jsou AFTER / BEFORE, poté při jaké akci INSERT / UPDATE / DELETE, následované klíčovým slovem ON a názvem tabulky, ke které bude vázán. Poté uvádíme klíčová slova FOR EACH ROW, která říkají že akce bude provedena tolikrát, kolik je ovlivněno řádků. Poté již mezi BEGIN a ENG následuje vlastní kód triggeru:

CREATE TRIGGER `Pocet_komentaru` AFTER INSERT ON `komentare`
FOR EACH ROW
BEGIN
UPDATE clanky
SET pocet_komentaru = (SELECT COUNT(clanek_id) FROM komentare WHERE clanek_id = clanky.clanek_id)
WHERE (clanek_id = new.clanek_id);
END


V kódu, který se stará o aktualizaci můžete vidět ještě jednu novou věc. Jde o použití virtuální tabulky new, která nám zpřístupňuje data v okamžiku po změně. Pokud bychom chtěli využít data před změnou, existuje ještě tabulka old.

Nyní máme vytvoření trigger pro přepočítávání komentářů u článků (pokud databáze vrací chybu je problém v oddělovači viz předchozí díl. Pokud byste se k němu chtěli vrátit třeba kvůli editaci, v PhpMyAdmin ho naleznete po rozkliknutí tabulky ve stromovému levém menu (v češtině jako spouště).

Pokud nyní vložíte nový řádek do tabulky komentare a podíváte se do tabulky clanky, uvidíte správně aktualizovaný počet komentářů o článků. Pokud byste ale některý z komentářů smazali, žádná aktualizace neproběhne, k tomu by bylo nutné vytvořit ještě trigger k DELETE.

Jak vidíte, triggery mohou být v mnoha případech užitečné. Mají ale i svou temnou stranu, mohou svádět k přenášení velké části logiky z aplikace do databáze, což (z mého pohledu) nepovažuji za šťastné.


Další díly tutoriálu

19. Transakce
20. Uložené procedury
21. Triggery
22. Uživatelsky definované funkce
23. Větvení kódu - podmínky a cykly