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 -p
Nastę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_database
uruchamiają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
stores
stół. 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
stores
tabeli, 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
products
stół. 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_name
pole określi nazwy pozycji. -
cost_price
iretail_price
pola określą odpowiednio cenę kupna i sprzedaży. -
availability
kolumna określi dostępność produktu w poszczególnych sklepach. Jeśli produkt jest dostępny tylko w naszym lokalnym sklepie (Filadelfia), oznaczymy go kodemLOCAL
wartość. W przeciwnym razie użyjemy wartościALL
aby oznaczyć produkt, który jest dostępny w obu sklepach (Filadelfia i Galloway).
-
-
Dodaj przykładowe dane do
products
tabela: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_id
zproducts
tabela istore_id
zestores
tabela, w której przedmiot jest dostępny.Utwórz
products_to_stores
tabeli, 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_products
stół. 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_history
tabela 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
:AlboBEFORE
lubAFTER
. -
TRIGGER_EVENT
:Musisz określić zdarzenie bazy danych, które wywoła wyzwalacz:INSERT
,UPDATE
lubDELETE
. -
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 zmieniaDELIMITER
z 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
NEW
słowo kluczowe, aby sprawdzićcost_price
iretail_price
przed wstawieniem rekordu doproducts
tabeli, używającIF...THEN...END IF
oświadczenie. -
Jeśli
cost_price
jest 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_validator
uruchom 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_validator
wyzwalacz, 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_delete
wyzwalacz, 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ą
ALL
w 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_availability
cyngiel. Ponieważ mamy wiele wierszy kodu w ciele wyzwalacza, użyjemyBEGIN...END
blok: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
products
tabeli, wyzwalacz sprawdziavailability
pole. -
Jeśli jest oznaczony
LOCAL
wartość, 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_availability
wyzwalacz 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_stores
tabela: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_updater
uruchom, 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_price
produktu wproducts_price_history
tabela.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_history
tabela, 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_archiver
uruchom 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łównychproducts
tabeli, nasz wyzwalacz automatycznie zarejestruje go warchived_products
tabela do wykorzystania w przyszłości. -
Następnie usuń produkt z
products
tabeli i zobacz, czy wyzwalacz zostanie wywołany:DELETE FROM products WHERE product_id='3';
-
Teraz, jeśli sprawdzisz
archived_products
tabeli, 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