wyzwalacz to predefiniowane polecenie SQL, które jest automatycznie wykonywane, gdy w bazie danych wystąpią określone działania. Może zostać uruchomiony przed lub po INSERT , UPDATE lub DELETE wydarzenie.
Wyzwalacze są używane głównie do utrzymania logiki oprogramowania na serwerze MySQL i mają kilka zalet:
-
Wyzwalacze pomagają scentralizować globalne operacje w jednym miejscu.
-
Redukują kod po stronie klienta i pomagają zminimalizować podróże w obie strony do serwera bazy danych.
-
Pomagają zwiększyć skalowalność aplikacji na różnych platformach.
Niektóre typowe przypadki użycia wyzwalaczy obejmują rejestrowanie audytu, wstępne obliczanie wartości bazy danych (np. sumy skumulowane) oraz egzekwowanie złożonych zasad integralności danych i walidacji.
Z tego przewodnika dowiesz się:
-
Jak zbudowana jest składnia wyzwalacza.
-
Jak tworzyć wyzwalacze, które są wykonywane przed wystąpieniem innych zdarzeń w bazie danych.
-
Jak tworzyć wyzwalacze, które są wykonywane po wystąpieniu innych zdarzeń w bazie danych.
-
Jak usunąć wyzwalacze.
Zanim zaczniesz
-
Jeśli jeszcze tego nie zrobiłeś, utwórz konto Linode i instancję obliczeniową. Zobacz nasze przewodniki Wprowadzenie do Linode i tworzenie instancji obliczeniowej.
-
Postępuj zgodnie z naszym przewodnikiem Konfigurowanie i zabezpieczanie instancji Compute, aby zaktualizować system. Możesz także ustawić strefę czasową, skonfigurować nazwę hosta, utworzyć ograniczone konto użytkownika i utwardzić dostęp SSH.
-
Serwer i klient MySQL zainstalowany na serwerze Linode. Instrukcje instalacji MySQL są dostępne dla różnych dystrybucji w naszej sekcji MySQL.
Przygotuj bazę danych
Aby lepiej zrozumieć, jak działają wyzwalacze, utworzymy przykładową bazę danych i dodamy do niej przykładowe dane. Później utworzymy różne wyzwalacze w bazie danych jako ćwiczenie weryfikacyjne.
-
Najpierw zaloguj się do serwera MySQL:
mysql -u root -pNastępnie wprowadź hasło roota swojego serwera MySQL i naciśnij Enter aby kontynuować.
-
Następnie zobaczysz monit MySQL podobny do pokazanego poniżej:
mysql > -
Utwórz
test_databaseuruchamiając poniższe polecenie:CREATE DATABASE test_database;Wyjście:
Query OK, 1 row affected (0.02 sec) -
Przejdź do bazy danych:
USE test_database;Wyjście:
Database changed -
Po wybraniu bazy danych utworzymy kilka tabel, których użyjemy do zademonstrowania wyzwalaczy. Zaczniemy od stworzenia
storesstół. Ta tabela zawiera informacje o dwóch przykładowych sklepach/biurach, z których nasza hipotetyczna firma prowadzi działalność:CREATE TABLE stores ( store_id BIGINT PRIMARY KEY AUTO_INCREMENT, store_name VARCHAR(50) ) ENGINE=InnoDB;Wyjście:
Query OK, 0 rows affected (0.07 sec) -
Następnie dodaj dwa rekordy do
storestabeli, uruchamiając poniższe polecenia:INSERT INTO stores (store_name) VALUES ('Philadelphia'); INSERT INTO stores (store_name) VALUES ('Galloway');Po każdym poleceniu otrzymasz następujące dane wyjściowe:
Query OK, 1 row affected (0.08 sec) ... -
Potwierdź rekordy, uruchamiając poniższe polecenie:
SELECT * FROM stores;Wyjście:
+----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec) -
Następnie utwórz
productsstół. Stół pomieści różne produkty oferowane w sklepie: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;Wyjście:
Query OK, 0 rows affected (0.13 sec)-
Każdy produkt będzie jednoznacznie identyfikowany przez
product_id. -
product_namepole określi nazwy pozycji. -
cost_priceiretail_pricepola określą odpowiednio cenę kupna i sprzedaży. -
availabilitykolumna określi dostępność produktu w poszczególnych sklepach. Jeśli produkt jest dostępny tylko w naszym lokalnym sklepie (Filadelfia), oznaczymy go kodemLOCALwartość. W przeciwnym razie użyjemy wartościALLaby oznaczyć produkt, który jest dostępny w obu sklepach (Filadelfia i Galloway).
-
-
Dodaj przykładowe dane do
productstabela: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');Otrzymasz wynik pokazany poniżej po każdym poleceniu wstawiania:
Query OK, 1 row affected (0.02 sec) ... -
Potwierdź, czy produkty zostały wstawione, uruchamiając poniższe polecenie:
SELECT * FROM products;Wyjście:
+------------+----------------+------------+--------------+--------------+ | 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) -
Następnie dostępność produktów zostanie zmapowana do innej tabeli o nazwie
products_to_stores. Ta tabela będzie po prostu odnosić się doproduct_idzproductstabela istore_idzestorestabela, w której przedmiot jest dostępny.Utwórz
products_to_storestabeli, uruchamiając poniższy kod:CREATE TABLE products_to_stores ( ref_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, store_id BIGINT ) ENGINE=InnoDB;Wyjście:
Query OK, 0 rows affected (0.14 sec) -
Następnie utworzymy
archived_productsstół. Tabela będzie zawierała informacje o usuniętych produktach do wykorzystania w przyszłości:CREATE TABLE archived_products ( product_id BIGINT PRIMARY KEY , product_name VARCHAR(40), cost_price DOUBLE, retail_price DOUBLE, availability VARCHAR(5) ) ENGINE=InnoDB;Wyjście:
Query OK, 0 rows affected (0.14 sec) -
Na koniec utworzymy
products_price_historytabela do śledzenia różnych cen każdego produktu w czasie:CREATE TABLE products_price_history ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, price_date DATETIME, retail_price DOUBLE ) ENGINE=InnoDB;Wyjście:
Query OK, 0 rows affected (0.14 sec)
Gdy nasza struktura bazy danych jest już gotowa, możemy teraz kontynuować naukę podstawowej składni wyzwalacza bazy danych MySQL, aby utworzyć naszą pierwszą próbkę.
Składnia wyzwalacza
Jak wskazano wcześniej, wyzwalacze są uruchamiane automatycznie przed lub po uruchomieniu polecenia SQL w bazie danych. Podstawowa składnia tworzenia wyzwalaczy jest następująca:
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
[TRIGGER BODY];
-
TRIGGER_NAME:Każdy wyzwalacz musi mieć unikalną nazwę i należy ją tutaj zdefiniować. -
TRIGGER_TIME:AlboBEFORElubAFTER. -
TRIGGER_EVENT:Musisz określić zdarzenie bazy danych, które wywoła wyzwalacz:INSERT,UPDATElubDELETE. -
TRIGGER BODY:Określa aktualne polecenie SQL (lub polecenia), które chcesz uruchomić przez wyzwalacz.
Jeśli treść wyzwalacza zawiera więcej niż jedną instrukcję SQL, musisz umieścić ją w BEGIN...END blok. Musisz także tymczasowo zmienić DELIMITER który sygnalizuje koniec korpusu wyzwalacza do nowej wartości. Gwarantuje to, że instrukcje w ciele nie zostaną przedwcześnie zinterpretowane przez klienta MySQL. Przykład tego wygląda następująco:
DELIMITER &&
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
BEGIN
[TRIGGER BODY]
END &&
DELIMITER ;
Uwaga Ostatnia linia tego przykładu zmieniaDELIMITERz powrotem do domyślnego;wartość.
Tworzenie przed wyzwalaczami zdarzeń
W tej sekcji przyjrzymy się różnym typom wyzwalaczy, które są uruchamiane przed operacją bazy danych. Należą do nich BEFORE INSERT , BEFORE UPDATE i BEFORE DELETE wyzwalacze.
Tworzenie wyzwalacza przed wstawieniem
Stworzymy nasz pierwszy BEFORE INSERT cyngiel. Wyzwalacz upewni się, że cena detaliczna produktu jest większa niż koszt własny za każdym razem, gdy elementy są wstawiane do products stół. W przeciwnym razie użytkownik bazy danych otrzyma błąd.
-
Będąc nadal na
mysql >wpisz polecenie poniżej: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 ;-
Powyższy kod definiuje nazwę wyzwalacza (
price_validator), czas (BEFORE), zdarzenie (INSERT) i tabelę (products), które mają zostać dotknięte. -
Nasz wyzwalacz używa
NEWsłowo kluczowe, aby sprawdzićcost_priceiretail_priceprzed wstawieniem rekordu doproductstabeli, używającIF...THEN...END IFoświadczenie. -
Jeśli
cost_pricejest większa lub równaretail price, nasze wyzwalacze nakazują MySQL, aby zgłosił niestandardowy wyjątek, instruując użytkownika, aby naprawił błąd.
-
-
Aby przetestować powyższy wyzwalacz, spróbuj wstawić produkt, który narusza regułę weryfikacji:
INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');Wyjście:
ERROR 1644 (45000): Retail price must be greater than cost price.Powyższe polecenia wstawiania powinny zakończyć się niepowodzeniem, ponieważ
retail_price(144.00) nie jest wyższa niżcost_price(145.00).
Tworzenie wyzwalacza przed aktualizacją
Następnie utworzymy BEFORE UPDATE cyngiel. Ten wyzwalacz uniemożliwi użytkownikom bazy danych edytowanie nazwy produktu po wstawieniu produktu do bazy danych. Jeśli w bazie danych pracuje wielu użytkowników, BEFORE UPDATE wyzwalacz może być użyty do ustawienia wartości tylko do odczytu, co może uniemożliwić złośliwym lub nieostrożnym użytkownikom niepotrzebną modyfikację rekordów.
-
Utwórz nowy
product_name_validatoruruchom poleceniem poniżej: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 ;Ten wyzwalacz porównuje wartości nowego
product_name(NEW.product_name) i stara nazwa już w bazie danych (OLD.product_name). W przypadku niezgodności zgłaszany jest wyjątek. -
Aby wywołać
product_name_validatorwyzwalacz, możemy spróbować zaktualizować nazwę produktu o identyfikatorze1:UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';Wyjście:
ERROR 1644 (45000): Product name is read-only and it can not be changed.
Definiowanie wyzwalacza przed usunięciem
W tej sekcji zobaczysz, jak zdefiniować BEFORE DELETE wyzwalacz, aby uniemożliwić użytkownikom usuwanie określonych rekordów z tabeli.
-
Aby utworzyć
prevent_deletewyzwalacz, uruchom poniższe polecenie: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 ;Ten wyzwalacz zapobiegnie produktom oznaczonym wartością
ALLw kolumnie dostępności przed usunięciem. -
Następnie spróbuj usunąć pierwszy produkt z tabeli produktów i sprawdź, czy wyzwalacz zostanie wywołany:
DELETE FROM products WHERE product_id='1';Wyjście:
ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.
Przyjrzeliśmy się różnym wyzwalaczom, które są wywoływane przed operacją bazy danych. Następnie przyjrzymy się innym typom wyzwalaczy, które są uruchamiane po zdarzeniach w bazie danych.
Tworzenie wyzwalaczy po zdarzeniu
W środowisku produkcyjnym możesz chcieć, aby niektóre wyzwalacze były uruchamiane automatycznie po wystąpieniu zdarzenia bazy danych (na przykład wstawienie rekordów do różnych tabel). Poniższe przykłady pokazują, jak tego rodzaju wyzwalacze mogą być używane w naszej przykładowej bazie danych.
Tworzenie wyzwalacza po wstawieniu
Ten przykład tworzy wyzwalacz o nazwie product_availability który wstawia rekordy mapowania do products_to_stores stół. Ten wyzwalacz służy do wymuszania logiki biznesowej; w szczególności pomaga określić dostępność produktów w różnych sklepach.
-
Uruchom poniższy kod, aby utworzyć
product_availabilitycyngiel. Ponieważ mamy wiele wierszy kodu w ciele wyzwalacza, użyjemyBEGIN...ENDblok: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 ;-
Gdy element jest wstawiany do
productstabeli, wyzwalacz sprawdziavailabilitypole. -
Jeśli jest oznaczony
LOCALwartość, produkt będzie dostępny tylko w jednym sklepie. -
Każda inna wartość poinstruuje wyzwalacz, aby udostępnił produkt w dwóch sklepach, które utworzyliśmy wcześniej.
-
-
Aby zobaczyć
product_availabilitywyzwalacz w akcji, wstaw dwa rekordy do tabeli produktów: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'); -
Następnie zapytaj
products_to_storestabela:SELECT * FROM products_to_stores;Powinieneś zobaczyć wyjście podobne do pokazanego poniżej:
+--------+------------+----------+ | ref_id | product_id | store_id | +--------+------------+----------+ | 1 | 4 | 1 | | 2 | 5 | 1 | | 3 | 5 | 2 | +--------+------------+----------+ 3 rows in set (0.00 sec)
Definiowanie wyzwalacza po aktualizacji
Wyzwalacz można również uruchomić po UPDATE wydarzenie. Zobaczymy, jak możemy wykorzystać ten rodzaj wyzwalacza, aby śledzić zmiany cen w naszym sklepie w czasie.
-
Utwórz
product_history_updateruruchom, uruchamiając poniższe polecenie: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);Ten wyzwalacz rejestruje zmiany
retail_priceproduktu wproducts_price_historytabela.Uwaga W przeciwieństwie do poprzednich przykładów, ten wyzwalacz ma tylko jedną instrukcję w ciele wyzwalacza, więc nie musimy zmieniać
DELIMITER. -
Następnie spróbuj zaktualizować cenę pierwszego produktu, uruchamiając poniższe polecenie:
UPDATE products SET retail_price='36.75' WHERE product_id='1'; -
Następnie zapytaj o
products_price_historytabela, aby sprawdzić, czy zmiana ceny została zarejestrowana:SELECT * FROM products_price_history;Jeśli wyzwalacz zadziałał zgodnie z oczekiwaniami, powinieneś otrzymać następujące dane wyjściowe:
+------------+---------------------+--------------+ | product_id | price_date | retail_price | +------------+---------------------+--------------+ | 1 | 2020-01-28 11:46:21 | 36.75 | +------------+---------------------+--------------+ 1 row in set (0.00 sec)
Tworzenie wyzwalacza po usunięciu
W niektórych przypadkach możesz chcieć rejestrować operacje usuwania po wykonaniu określonej akcji w bazie danych. Możesz to osiągnąć, używając AFTER DELETE wyzwalacz.
-
Utwórz nowy
product_archiveruruchom poleceniem poniżej: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);Ten wyzwalacz archiwizuje usunięte produkty w osobnej tabeli o nazwie
archived_products. Gdy element zostanie usunięty z głównychproductstabeli, nasz wyzwalacz automatycznie zarejestruje go warchived_productstabela do wykorzystania w przyszłości. -
Następnie usuń produkt z
productstabeli i zobacz, czy wyzwalacz zostanie wywołany:DELETE FROM products WHERE product_id='3'; -
Teraz, jeśli sprawdzisz
archived_productstabeli, powinieneś zobaczyć jeden rekord:SELECT * FROM archived_products;Wyjście:
+------------+--------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+--------------+------------+--------------+--------------+ | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+--------------+------------+--------------+--------------+ 1 row in set (0.00 sec)
Usuwanie wyzwalacza
Widziałeś różne typy wyzwalaczy i sposoby ich użycia w środowisku produkcyjnym. Czasami możesz chcieć usunąć wyzwalacz z bazy danych.
Możesz usunąć wyzwalacz, jeśli nie chcesz go już używać, korzystając z poniższej składni:
DROP TRIGGER IF EXISTS TRIGGER_NAME;
Uwaga IF EXISTS słowo kluczowe jest parametrem opcjonalnym, który usuwa wyzwalacz tylko, jeśli istnieje.
Na przykład, aby usunąć product_archiving wyzwalacz, który zdefiniowaliśmy powyżej, użyj poniższego polecenia:
DROP TRIGGER IF EXISTS product_archiver;
Wyjście:
Query OK, 0 rows affected (0.00 sec) Uwaga Zachowaj ostrożność podczas usuwania tabel powiązanych z wyzwalaczami. Gdy tabela zostanie usunięta z bazy danych MySQL, powiązane wyzwalacze są również automatycznie usuwane.
Więcej informacji
Dodatkowe informacje na ten temat można znaleźć w poniższych zasobach. Chociaż są one dostarczane w nadziei, że będą przydatne, należy pamiętać, że nie możemy ręczyć za dokładność ani aktualność materiałów hostowanych zewnętrznie.
- Składnia i przykłady wyzwalaczy MySQL