spouštěč je předdefinovaný příkaz SQL, který se automaticky provede, když v databázi nastanou určité akce. Může být spuštěn buď před nebo po INSERT , UPDATE nebo DELETE událost.
Spouštěče se používají hlavně k udržování softwarové logiky na serveru MySQL a mají několik výhod:
-
Spouštěče pomáhají udržet globální operace centralizované na jednom místě.
-
Redukují kód na straně klienta a pomáhají minimalizovat zpáteční cesty k databázovému serveru.
-
Pomáhají dělat aplikace škálovatelnější na různých platformách.
Některé běžné případy použití spouštěčů zahrnují protokolování auditu, předvýpočet databázových hodnot (např. kumulativní součty) a vynucení komplexních pravidel integrity dat a ověřování.
V této příručce se dozvíte:
-
Jak je strukturována syntaxe spouštěče.
-
Jak vytvořit spouštěče, které se spouštějí předtím, než nastanou jiné databázové události.
-
Jak vytvořit spouštěče, které se spouštějí po výskytu jiných databázových událostí.
-
Jak odstranit spouštěče.
Než začnete
-
Pokud jste tak ještě neučinili, vytvořte si účet Linode a Compute Instance. Podívejte se na naše příručky Začínáme s Linode a Vytvoření výpočetní instance.
-
Při aktualizaci systému postupujte podle našeho průvodce nastavením a zabezpečením výpočetní instance. Můžete také chtít nastavit časové pásmo, nakonfigurovat název hostitele, vytvořit omezený uživatelský účet a posílit přístup SSH.
-
Server a klient MySQL nainstalovaný na serveru Linode. Instalační příručky pro MySQL jsou k dispozici pro různé distribuce v naší sekci MySQL.
Příprava databáze
Abychom lépe porozuměli tomu, jak triggery fungují, vytvoříme vzorovou databázi a přidáme do ní vzorová data. Později v databázi vytvoříme různé spouštěče jako důkaz koncepčního cvičení.
-
Nejprve se přihlaste k serveru MySQL:
mysql -u root -pPoté zadejte heslo uživatele root vašeho serveru MySQL a stiskněte Enter pokračovat.
-
Dále uvidíte výzvu MySQL podobnou té, která je zobrazena níže:
mysql > -
Vytvořte
test_databasespuštěním příkazu níže:CREATE DATABASE test_database;Výstup:
Query OK, 1 row affected (0.02 sec) -
Přepnout do databáze:
USE test_database;Výstup:
Database changed -
Jakmile je databáze vybrána, vytvoříme nějaké tabulky, které použijeme pro demonstraci spouštěčů. Začneme vytvořením
storesstůl. Tato tabulka bude obsahovat informace o dvou vzorových prodejnách/kancelářích, z nichž naše hypotetická obchodní činnost působí:CREATE TABLE stores ( store_id BIGINT PRIMARY KEY AUTO_INCREMENT, store_name VARCHAR(50) ) ENGINE=InnoDB;Výstup:
Query OK, 0 rows affected (0.07 sec) -
Dále přidejte dva záznamy do
storestabulky spuštěním následujících příkazů:INSERT INTO stores (store_name) VALUES ('Philadelphia'); INSERT INTO stores (store_name) VALUES ('Galloway');Po každém příkazu získáte následující výstup:
Query OK, 1 row affected (0.08 sec) ... -
Potvrďte záznamy spuštěním příkazu níže:
SELECT * FROM stores;Výstup:
+----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec) -
Dále vytvořte
productsstůl. Na stole budou různé produkty nabízené v obchodě:CREATE TABLE products ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_name VARCHAR(40), cost_price DOUBLE, retail_price DOUBLE, availability VARCHAR(5) ) ENGINE=InnoDB;Výstup:
Query OK, 0 rows affected (0.13 sec)-
Každý produkt bude jednoznačně identifikován pomocí
product_id. -
product_namepole bude specifikovat názvy položek. -
cost_pricearetail_pricepole určí kupní a prodejní cenu. -
availabilitybude definovat dostupnost produktu v různých obchodech. Pokud je produkt dostupný pouze v našem místním obchodě (Philadelphia), označíme jejLOCALhodnota. Jinak použijeme hodnotuALLoznačovat produkt, který je dostupný v obou obchodech (Philadelphia a Galloway).
-
-
Přidejte ukázková data do
productstabulka:INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('WIRELESS MOUSE', '18.23', '30.25','ALL'); INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('8 MP CAMERA', '60.40', '85.40','ALL'); INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('SMART WATCH', '189.60', '225.30','LOCAL');Po každém příkazu vložení získáte výstup zobrazený níže:
Query OK, 1 row affected (0.02 sec) ... -
Potvrďte, zda byly produkty vloženy spuštěním příkazu níže:
SELECT * FROM products;Výstup:
+------------+----------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+----------------+------------+--------------+--------------+ | 1 | WIRELESS MOUSE | 18.23 | 30.25 | ALL | | 2 | 8 MP CAMERA | 60.4 | 85.4 | ALL | | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+----------------+------------+--------------+--------------+ 3 rows in set (0.00 sec) -
Dále bude dostupnost produktů mapována do další tabulky s názvem
products_to_stores. Tato tabulka bude pouze odkazovat naproduct_idzproductstabulkou astore_idzstorestabulka, kde je položka dostupná.Vytvořte
products_to_storestabulky spuštěním kódu níže:CREATE TABLE products_to_stores ( ref_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, store_id BIGINT ) ENGINE=InnoDB;Výstup:
Query OK, 0 rows affected (0.14 sec) -
Dále vytvoříme
archived_productsstůl. Tabulka bude obsahovat informace o odstraněných produktech pro budoucí použití:CREATE TABLE archived_products ( product_id BIGINT PRIMARY KEY , product_name VARCHAR(40), cost_price DOUBLE, retail_price DOUBLE, availability VARCHAR(5) ) ENGINE=InnoDB;Výstup:
Query OK, 0 rows affected (0.14 sec) -
Nakonec vytvoříme
products_price_historytabulka pro sledování různých cen jednotlivých produktů v průběhu času:CREATE TABLE products_price_history ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, price_date DATETIME, retail_price DOUBLE ) ENGINE=InnoDB;Výstup:
Query OK, 0 rows affected (0.14 sec)
Jakmile je struktura naší databáze na místě, můžeme nyní pokračovat a naučit se základní syntaxi spouštěče databáze MySQL, abychom vytvořili naši první ukázku.
Syntaxe spouštěče
Jak bylo uvedeno výše, spouštěče jsou spouštěny automaticky buď před nebo po spuštění příkazu SQL v databázi. Základní syntaxe pro vytváření spouštěčů je následující:
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
[TRIGGER BODY];
-
TRIGGER_NAME:Každý spouštěč musí mít jedinečný název a měli byste jej definovat zde. -
TRIGGER_TIME:BuďBEFOREneboAFTER. -
TRIGGER_EVENT:Musíte zadat databázovou událost, která vyvolá spouštěč:INSERT,UPDATEneboDELETE. -
TRIGGER BODY:Toto specifikuje skutečný SQL příkaz (nebo příkazy), které chcete spouštět vaším spouštěčem.
Pokud má tělo spouštěče více než jeden příkaz SQL, musíte jej uzavřít do BEGIN...END blok. Také budete muset dočasně změnit DELIMITER která signalizuje konec těla spouště na novou hodnotu. To zajišťuje, že příkazy v těle nebudou předčasně interpretovány vaším MySQL klientem. Příklad vypadá takto:
DELIMITER &&
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
BEGIN
[TRIGGER BODY]
END &&
DELIMITER ;
Poznámka Poslední řádek tohoto příkladu změníDELIMITERzpět na výchozí;hodnotu.
Vytvoření před spouštěči událostí
V této části se podíváme na různé typy spouštěčů, které se spouštějí před operací databáze. Patří mezi ně BEFORE INSERT , BEFORE UPDATE a BEFORE DELETE spouští.
Vytvoření spouštěče před vložením
Vytvoříme náš první BEFORE INSERT spoušť. Spouštěč zajistí, aby maloobchodní cena produktu byla vyšší než nákladová cena, kdykoli jsou položky vloženy do products stůl. Jinak se uživateli databáze zobrazí chyba.
-
Ještě na
mysql >zadejte následující příkaz:DELIMITER $$ CREATE TRIGGER price_validator BEFORE INSERT ON products FOR EACH ROW IF NEW.cost_price>=NEW.retail_price THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Retail price must be greater than cost price.'; END IF $$ DELIMITER ;-
Výše uvedený kód definuje název spouštěče (
price_validator), čas (BEFORE), událost (INSERT) a tabulku (products), která má být ovlivněna. -
Náš spouštěč používá
NEWklíčové slovo pro kontrolucost_pricearetail_pricepřed vložením záznamu doproductspomocí tabulkyIF...THEN...END IFprohlášení. -
Pokud
cost_priceje větší nebo rovnaretail price, naše spouštěče sdělují MySQL, aby vyvolalo vlastní výjimku, která uživateli dá pokyn, aby chybu napravil.
-
-
Chcete-li výše uvedený spouštěč otestovat, zkuste vložit produkt, který porušuje ověřovací pravidlo:
INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');Výstup:
ERROR 1644 (45000): Retail price must be greater than cost price.Výše uvedené příkazy vložení by měly selhat, protože
retail_price(144,00) není větší nežcost_price(145,00).
Vytvoření spouštěče před aktualizací
Dále vytvoříme BEFORE UPDATE spoušť. Tento spouštěč zabrání uživatelům databáze upravovat název produktu, jakmile je produkt vložen do databáze. Pokud v databázi pracuje více uživatelů, BEFORE UPDATE spouštěč může být použit k tomu, aby byly hodnoty pouze pro čtení, což může zabránit zlomyslným nebo neopatrným uživatelům zbytečně upravovat záznamy.
-
Vytvořte nový
product_name_validatorspusťte příkazem níže:DELIMITER $$ CREATE TRIGGER product_name_validator BEFORE UPDATE ON products FOR EACH ROW IF NEW.product_name<>OLD.product_name THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Product name is read-only and it can not be changed.'; END IF $$ DELIMITER ;Toto pravidlo porovnává hodnoty nového
product_name(NEW.product_name) a starý název, který je již v databázi (OLD.product_name). Pokud dojde k neshodě, je vyvolána výjimka. -
Chcete-li vyvolat
product_name_validatorspouštěče, můžeme se pokusit aktualizovat název produktu pomocí ID1:UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';Výstup:
ERROR 1644 (45000): Product name is read-only and it can not be changed.
Definování spouštěče před odstraněním
V této části uvidíte, jak můžete definovat BEFORE DELETE spouštěč, který uživatelům zabrání ve smazání konkrétních záznamů z tabulky.
-
Chcete-li vytvořit
prevent_deletespusťte níže uvedený příkaz:DELIMITER $$ CREATE TRIGGER prevent_delete BEFORE DELETE ON products FOR EACH ROW IF OLD.availability='ALL' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'The product can not be deleted because it is available in ALL stores.'; END IF $$ DELIMITER ;Toto pravidlo zabrání produktům označeným hodnotou
ALLve sloupci dostupnosti, aby nebyly odstraněny. -
Dále se pokuste odstranit první produkt z tabulky produktů a zjistěte, zda bude spouštěč vyvolán:
DELETE FROM products WHERE product_id='1';Výstup:
ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.
Podívali jsme se na různé spouštěče, které se vyvolávají před operací databáze. Dále se podíváme na další typy spouštěčů, které se spouštějí po událostech databáze.
Vytvoření spouštěčů po událostech
V produkčním prostředí můžete chtít, aby se některé spouštěče automaticky spouštěly po výskytu databázové události (například vkládání záznamů do různých tabulek). Níže uvedené příklady ukazují, jak lze tyto druhy spouštěčů použít v naší vzorové databázi.
Vytvoření spouštěče po vložení
Tento příklad vytvoří pravidlo s názvem product_availability který vloží mapovací záznamy do products_to_stores stůl. Tento spouštěč se používá k vynucení obchodní logiky; zejména pomáhá definovat dostupnost produktů pro různé obchody.
-
Spuštěním níže uvedeného kódu vytvořte
product_availabilityspoušť. Protože v těle spouštěče máme více řádků kódu, použijemeBEGIN...ENDblokovat:DELIMITER $$ CREATE TRIGGER product_availability AFTER INSERT ON products FOR EACH ROW BEGIN IF NEW.availability='LOCAL' then INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1'); ELSE INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1'); INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '2'); END IF; END $$ DELIMITER ;-
Když je položka vkládána do
productstabulka, spouštěč zkontrolujeavailabilitypole. -
Pokud je označena
LOCALhodnotu, bude produkt dostupný pouze v jednom obchodě. -
Jakákoli jiná hodnota dá spouštěči pokyn, aby zpřístupnil produkt dvěma obchodům, které jsme vytvořili dříve.
-
-
Chcete-li zobrazit
product_availabilitytrigger v akci, vložte dva záznamy do tabulky produktů:INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('BLUETOOTH KEYBOARD', '17.60', '23.30','LOCAL'); INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('DVB-T2 RECEIVE', '49.80', '53.40','ALL'); -
Poté zadejte dotaz na
products_to_storestabulka:SELECT * FROM products_to_stores;Měli byste vidět výstup podobný tomu zobrazenému níže:
+--------+------------+----------+ | ref_id | product_id | store_id | +--------+------------+----------+ | 1 | 4 | 1 | | 2 | 5 | 1 | | 3 | 5 | 2 | +--------+------------+----------+ 3 rows in set (0.00 sec)
Definování spouštěče po aktualizaci
Spouštěč lze spustit také po UPDATE událost. Uvidíme, jak můžeme tento typ spouštěče využít ke sledování změn cen v našem obchodě v průběhu času.
-
Vytvořte
product_history_updaterspustit spuštěním příkazu níže:CREATE TRIGGER product_history_updater AFTER UPDATE ON products FOR EACH ROW INSERT INTO products_price_history (product_id, price_date, retail_price) VALUES (OLD.product_id, NOW(), NEW.retail_price);Tento spouštěč zaznamenává změny
retail_priceproduktu vproducts_price_historytabulka.Poznámka Na rozdíl od předchozích příkladů má toto pravidlo pouze jeden příkaz v těle spouštěče, takže nemusíme měnit
DELIMITER. -
Poté zkuste aktualizovat cenu prvního produktu spuštěním příkazu níže:
UPDATE products SET retail_price='36.75' WHERE product_id='1'; -
Dále se zeptejte
products_price_historytabulka, abyste zjistili, zda byla zaznamenána změna ceny:SELECT * FROM products_price_history;Pokud spoušť fungovala podle očekávání, měli byste získat následující výstup:
+------------+---------------------+--------------+ | product_id | price_date | retail_price | +------------+---------------------+--------------+ | 1 | 2020-01-28 11:46:21 | 36.75 | +------------+---------------------+--------------+ 1 row in set (0.00 sec)
Vytvoření spouštěče po odstranění
V některých případech můžete chtít zaznamenat operace odstranění poté, co v databázi došlo k určité akci. Toho lze dosáhnout pomocí AFTER DELETE spoušť.
-
Vytvořte nový
product_archiverspusťte příkazem níže:CREATE TRIGGER product_archiver AFTER DELETE ON products FOR EACH ROW INSERT INTO archived_products (product_id, product_name, cost_price, retail_price, availability) VALUES (OLD.product_id, OLD.product_name, OLD.cost_price, OLD.retail_price, OLD.availability);Tento spouštěč archivuje smazané produkty do samostatné tabulky s názvem
archived_products. Když je položka odstraněna z hlavníchproductsnáš spouštěč jej automaticky zaznamená doarchived_productstabulka pro budoucí použití. -
Dále odstraňte produkt z
productstabulky a zjistěte, zda bude spouštěč vyvolán:DELETE FROM products WHERE product_id='3'; -
Nyní, když zaškrtnete
archived_productstabulky, měli byste vidět jeden záznam:SELECT * FROM archived_products;Výstup:
+------------+--------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+--------------+------------+--------------+--------------+ | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+--------------+------------+--------------+--------------+ 1 row in set (0.00 sec)
Odstranění spouštěče
Viděli jste různé typy spouštěčů a jak je lze použít v produkčním prostředí. Někdy můžete chtít odstranit spouštěč z databáze.
Pokud spouštěč již nechcete používat, můžete jej smazat pomocí níže uvedené syntaxe:
DROP TRIGGER IF EXISTS TRIGGER_NAME;
Poznámka IF EXISTS klíčové slovo je volitelný parametr, který smaže spouštěč, pouze pokud existuje.
Chcete-li například odstranit product_archiving trigger, který jsme definovali výše, použijte níže uvedený příkaz:
DROP TRIGGER IF EXISTS product_archiver;
Výstup:
Query OK, 0 rows affected (0.00 sec) Pozor Při odstraňování tabulek spojených se spouštěči buďte opatrní. Jakmile je tabulka odstraněna z databáze MySQL, související spouštěče jsou také automaticky odstraněny.
Další informace
Další informace o tomto tématu můžete získat v následujících zdrojích. Přestože jsou poskytovány v naději, že budou užitečné, vezměte prosím na vědomí, že nemůžeme ručit za přesnost nebo aktuálnost externě hostovaných materiálů.
- Syntaxe a příklady spouštěče MySQL