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 -p
Poté 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_database
spuš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
stores
stů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
stores
tabulky 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
products
stů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_name
pole bude specifikovat názvy položek. -
cost_price
aretail_price
pole určí kupní a prodejní cenu. -
availability
bude definovat dostupnost produktu v různých obchodech. Pokud je produkt dostupný pouze v našem místním obchodě (Philadelphia), označíme jejLOCAL
hodnota. Jinak použijeme hodnotuALL
označovat produkt, který je dostupný v obou obchodech (Philadelphia a Galloway).
-
-
Přidejte ukázková data do
products
tabulka: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_id
zproducts
tabulkou astore_id
zstores
tabulka, kde je položka dostupná.Vytvořte
products_to_stores
tabulky 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_products
stů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_history
tabulka 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ďBEFORE
neboAFTER
. -
TRIGGER_EVENT
:Musíte zadat databázovou událost, která vyvolá spouštěč:INSERT
,UPDATE
neboDELETE
. -
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íDELIMITER
zpě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á
NEW
klíčové slovo pro kontrolucost_price
aretail_price
před vložením záznamu doproducts
pomocí tabulkyIF...THEN...END IF
prohlášení. -
Pokud
cost_price
je 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_validator
spusť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_validator
spouš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_delete
spusť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
ALL
ve 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_availability
spoušť. Protože v těle spouštěče máme více řádků kódu, použijemeBEGIN...END
blokovat: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
products
tabulka, spouštěč zkontrolujeavailability
pole. -
Pokud je označena
LOCAL
hodnotu, 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_availability
trigger 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_stores
tabulka: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_updater
spustit 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_price
produktu vproducts_price_history
tabulka.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_history
tabulka, 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_archiver
spusť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íchproducts
náš spouštěč jej automaticky zaznamená doarchived_products
tabulka pro budoucí použití. -
Dále odstraňte produkt z
products
tabulky a zjistěte, zda bude spouštěč vyvolán:DELETE FROM products WHERE product_id='3';
-
Nyní, když zaškrtnete
archived_products
tabulky, 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