Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Praca z wyzwalaczami w bazie danych MySQL — samouczek

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

  1. Jeśli jeszcze tego nie zrobiłeś, utwórz konto Linode i instancję obliczeniową. Zobacz nasze przewodniki Wprowadzenie do Linode i tworzenie instancji obliczeniowej.

  2. 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.

  3. 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.

  1. 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ć.

  2. Następnie zobaczysz monit MySQL podobny do pokazanego poniżej:

    mysql >
  3. Utwórz test_database uruchamiając poniższe polecenie:

    CREATE DATABASE test_database;
    

    Wyjście:

    Query OK, 1 row affected (0.02 sec)
  4. Przejdź do bazy danych:

    USE test_database;
    

    Wyjście:

    Database changed
  5. 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)
  6. 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)
    ...
  7. 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)
  8. 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 i retail_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 kodem LOCAL wartość. W przeciwnym razie użyjemy wartości ALL aby oznaczyć produkt, który jest dostępny w obu sklepach (Filadelfia i Galloway).

  9. 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)
    ...
  10. 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)
  11. Następnie dostępność produktów zostanie zmapowana do innej tabeli o nazwie products_to_stores . Ta tabela będzie po prostu odnosić się do product_id z products tabela i store_id ze stores 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)
  12. 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)
  13. 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 :Albo BEFORE lub AFTER .

  • TRIGGER_EVENT :Musisz określić zdarzenie bazy danych, które wywoła wyzwalacz:INSERT , UPDATE lub DELETE .

  • 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 zmienia DELIMITER 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.

  1. 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 i retail_price przed wstawieniem rekordu do products tabeli, używając IF...THEN...END IF oświadczenie.

    • Jeśli cost_price jest większa lub równa retail price , nasze wyzwalacze nakazują MySQL, aby zgłosił niestandardowy wyjątek, instruując użytkownika, aby naprawił błąd.

  2. 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.

  1. 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.

  2. Aby wywołać product_name_validator wyzwalacz, możemy spróbować zaktualizować nazwę produktu o identyfikatorze 1 :

    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.

  1. 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.

  2. 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.

  1. Uruchom poniższy kod, aby utworzyć product_availability cyngiel. Ponieważ mamy wiele wierszy kodu w ciele wyzwalacza, użyjemy BEGIN...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 sprawdzi availability 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.

  2. 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');
    
  3. 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.

  1. 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 w products_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 .
  2. Następnie spróbuj zaktualizować cenę pierwszego produktu, uruchamiając poniższe polecenie:

    UPDATE products SET retail_price='36.75' WHERE product_id='1';
    
  3. 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.

  1. 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łównych products tabeli, nasz wyzwalacz automatycznie zarejestruje go w archived_products tabela do wykorzystania w przyszłości.

  2. Następnie usuń produkt z products tabeli i zobacz, czy wyzwalacz zostanie wywołany:

    DELETE FROM products WHERE product_id='3';
    
  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

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Najlepsze praktyki dotyczące długości kolumny varchar SQL

  2. Jak najlepiej wykorzystać funkcję komentowania w MySQL?

  3. Jak zresetować/zmienić wiersz poleceń MySql root w wierszu poleceń ubuntu linux?

  4. Błąd instalacji mysql-python:nie można otworzyć pliku dołączanego „config-win.h”

  5. Jak używać instrukcji CASE w MySQL