Задействане е предварително дефинирана SQL команда, която се изпълнява автоматично, когато се появят конкретни действия в базата данни. Може да се задейства преди или след INSERT
, UPDATE
или DELETE
събитие.
Тригерите се използват главно за поддържане на софтуерната логика в MySQL сървъра и имат няколко предимства:
-
Тригерите помагат да се поддържат централизирани глобални операции на едно място.
-
Те намаляват кода от страна на клиента и помагат да се сведат до минимум пътуванията до сървъра на базата данни.
-
Те помагат да се направят приложенията по-мащабируеми в различни платформи.
Някои често срещани случаи на използване на задействания включват регистриране на одит, предварително изчисляване на стойности на базата данни (напр. кумулативни суми) и налагане на сложни правила за целостта на данните и валидиране.
В това ръководство ще научите:
-
Как е структуриран синтаксисът за тригер.
-
Как да създадете тригери, които се изпълняват преди да възникнат други събития в базата данни.
-
Как да създадете тригери, които се изпълняват след възникване на други събития в базата данни.
-
Как да изтриете тригери.
Преди да започнете
-
Ако все още не сте го направили, създайте акаунт в Linode и Compute Instance. Вижте нашите ръководства Първи стъпки с Linode и Създаване на изчислителен екземпляр.
-
Следвайте нашето ръководство за настройка и осигуряване на изчислителен екземпляр, за да актуализирате вашата система. Може също да пожелаете да зададете часовата зона, да конфигурирате името на хоста си, да създадете ограничен потребителски акаунт и да укрепите SSH достъпа.
-
MySQL сървър и клиент, инсталирани на сървъра на Linode. Ръководствата за инсталиране на MySQL са налични за различни дистрибуции в нашия раздел MySQL.
Подгответе базата данни
За да разберем по-добре как работят тригерите, ще създадем примерна база данни и ще добавим примерни данни в нея. По-късно ще създадем различни тригери в базата данни като доказателство за упражнение на концепцията.
-
Първо, влезте във вашия MySQL сървър:
mysql -u root -p
След това въведете root паролата на вашия MySQL сървър и натиснете Enter за да продължите.
-
След това ще видите подкана за MySQL, подобна на показаната по-долу:
mysql >
-
Създайте
test_database
като изпълните командата по-долу:CREATE DATABASE test_database;
Изход:
Query OK, 1 row affected (0.02 sec)
-
Превключете към базата данни:
USE test_database;
Изход:
Database changed
-
След като базата данни бъде избрана, ще създадем някои таблици, които ще използваме за демонстриране на тригери. Ще започнем със създаване на
stores
маса. Тази таблица ще съдържа информация за два примерни магазина/офиси, от които работи нашият хипотетичен бизнес:CREATE TABLE stores ( store_id BIGINT PRIMARY KEY AUTO_INCREMENT, store_name VARCHAR(50) ) ENGINE=InnoDB;
Изход:
Query OK, 0 rows affected (0.07 sec)
-
След това добавете два записа към
stores
таблица, като изпълните командите по-долу:INSERT INTO stores (store_name) VALUES ('Philadelphia'); INSERT INTO stores (store_name) VALUES ('Galloway');
След всяка команда ще получите следния изход:
Query OK, 1 row affected (0.08 sec) ...
-
Потвърдете записите, като изпълните командата по-долу:
SELECT * FROM stores;
Изход:
+----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec)
-
След това създайте
products
маса. Таблицата ще съдържа различни продукти, които се предлагат в магазина: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;
Изход:
Query OK, 0 rows affected (0.13 sec)
-
Всеки продукт ще бъде уникално идентифициран чрез
product_id
. -
product_name
полето ще посочи имената на елементите. -
cost_price
иretail_price
полета ще определят съответно покупната и продажната цена. -
availability
колона ще определи наличността на продукта в различните магазини. Ако продуктът се предлага само в нашия местен магазин (Филаделфия), ние ще го обозначим сLOCAL
стойност. В противен случай ще използваме стойността наALL
за означаване на продукт, който се предлага и в двата магазина (Филаделфия и Галоуей).
-
-
Добавете примерни данни към
products
таблица: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');
Ще получите изхода, показан по-долу след всяка команда за вмъкване:
Query OK, 1 row affected (0.02 sec) ...
-
Потвърдете дали продуктите са били вмъкнати, като изпълните командата по-долу:
SELECT * FROM products;
Изход:
+------------+----------------+------------+--------------+--------------+ | 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)
-
След това наличността на продуктите ще бъде съпоставена с друга таблица с име
products_to_stores
. Тази таблица просто ще препраща къмproduct_id
отproducts
таблица иstore_id
отstores
таблица, където артикулът е наличен.Създайте
products_to_stores
таблица, като изпълните кода по-долу:CREATE TABLE products_to_stores ( ref_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, store_id BIGINT ) ENGINE=InnoDB;
Изход:
Query OK, 0 rows affected (0.14 sec)
-
След това ще създадем
archived_products
маса. Таблицата ще съдържа информация за изтрити продукти за бъдещи справки:CREATE TABLE archived_products ( product_id BIGINT PRIMARY KEY , product_name VARCHAR(40), cost_price DOUBLE, retail_price DOUBLE, availability VARCHAR(5) ) ENGINE=InnoDB;
Изход:
Query OK, 0 rows affected (0.14 sec)
-
И накрая, ще създадем
products_price_history
таблица за проследяване на различните цени на всеки продукт във времето:CREATE TABLE products_price_history ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, price_date DATETIME, retail_price DOUBLE ) ENGINE=InnoDB;
Изход:
Query OK, 0 rows affected (0.14 sec)
След като структурата на нашата база данни е на мястото си, вече можем да продължим напред и да научим основния синтаксис на задействане на MySQL база данни, за да създадем първата си извадка.
Синтаксис на задействане
Както беше посочено по-рано, тригерите се задействат автоматично преди или след изпълнение на SQL команда в базата данни. Основният синтаксис за създаване на тригери е както следва:
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
[TRIGGER BODY];
-
TRIGGER_NAME
:Всеки тригер трябва да има уникално име и трябва да го дефинирате тук. -
TRIGGER_TIME
:ИлиBEFORE
илиAFTER
. -
TRIGGER_EVENT
:Трябва да посочите събитието в базата данни, което ще извика тригера:INSERT
,UPDATE
илиDELETE
. -
TRIGGER BODY
:Това посочва действителната SQL команда (или команди), която искате да се изпълняват от вашия тригер.
Ако едно тригерно тяло има повече от един SQL израз, трябва да го затворите в BEGIN...END
блок. Освен това ще трябва временно да промените DELIMITER
което сигнализира края на тялото на тригера към нова стойност. Това гарантира, че изразите в тялото няма да бъдат интерпретирани преждевременно от вашия MySQL клиент. Пример за това изглежда по следния начин:
DELIMITER &&
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
BEGIN
[TRIGGER BODY]
END &&
DELIMITER ;
Забележка Последният ред от този пример променяDELIMITER
обратно към;
по подразбиране стойност.
Създаване преди задействане на събитие
В този раздел ще разгледаме различните типове тригери, които се задействат преди операция с база данни. Те включват BEFORE INSERT
, BEFORE UPDATE
и BEFORE DELETE
тригери.
Създаване на тригер преди вмъкване
Ще създадем нашия първи BEFORE INSERT
задействане. Задействането ще гарантира, че цената на дребно на даден продукт е по-висока от себестойността, когато артикулите се вмъкват в products
маса. В противен случай потребителят на базата данни ще получи грешка.
-
Докато все още сте в
mysql >
подкана, въведете командата по-долу: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 ;
-
Горният код дефинира името на тригера (
price_validator
), време (BEFORE
), събитие (INSERT
), и таблицата (products
) да бъдат засегнати. -
Нашият тригер използва
NEW
ключова дума, за да проверитеcost_price
иretail_price
преди да се вмъкне запис вproducts
таблица, като използватеIF...THEN...END IF
изявление. -
Ако
cost_price
е по-голямо или равно наretail price
, нашите тригери казват на MySQL да изведе персонализирано изключение, инструктиращо потребителя да коригира грешката.
-
-
За да тествате задействането по-горе, опитайте да вмъкнете продукт, който нарушава правилото за валидиране:
INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
Изход:
ERROR 1644 (45000): Retail price must be greater than cost price.
Горните команди за вмъкване трябва да се провалят, защото
retail_price
(144,00) не е по-голямо отcost_price
(145,00).
Създаване на тригер преди актуализиране
След това ще създадем BEFORE UPDATE
задействане. Този тригер ще попречи на потребителите на база данни да редактират име на продукт, след като продуктът е вмъкнат в базата данни. Ако имате няколко потребители, работещи в базата данни, BEFORE UPDATE
тригерът може да се използва за правене на стойности само за четене и това може да попречи на злонамерени или невнимателни потребители да променят ненужно записи.
-
Създайте нов
product_name_validator
задействайте с командата по-долу: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 ;
Този тригер сравнява стойностите на новия
product_name
(NEW.product_name
) и старото име, което вече е в базата данни (OLD.product_name
). Ако има несъответствие, се създава изключение. -
За да извикате
product_name_validator
тригер, можем да се опитаме да актуализираме името на продукта с идентификатор1
:UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
Изход:
ERROR 1644 (45000): Product name is read-only and it can not be changed.
Дефиниране на тригер преди изтриване
В този раздел ще видите как можете да дефинирате BEFORE DELETE
тригер, за да попречи на потребителите да изтриват конкретни записи от таблица.
-
За да създадете
prevent_delete
тригер, изпълнете командата по-долу: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 ;
Това задействане ще предотврати продукти, маркирани със стойност
ALL
в колоната наличност от изтриване. -
След това опитайте да изтриете първия продукт от таблицата с продукти и вижте дали тригерът ще бъде извикан:
DELETE FROM products WHERE product_id='1';
Изход:
ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.
Разгледахме различните тригери, които се извикват преди операция с база данни. След това ще разгледаме другите типове тригери, които се задействат след събития в базата данни.
Създаване на тригери след събитие
В производствена среда може да искате някои тригери да се изпълняват автоматично след възникване на събитие в базата данни (например вмъкване на записи в различни таблици). Примерите по-долу показват как тези видове тригери могат да се използват в нашата примерна база данни.
Създаване на тригер след вмъкване
Този пример създава тригер с име product_availability
който вмъква записи за съпоставяне в products_to_stores
маса. Този тригер се използва за налагане на бизнес логиката; по-специално, това помага да се определи наличността на продукти за различните магазини.
-
Изпълнете кода по-долу, за да създадете
product_availability
задействане. Тъй като имаме няколко реда код в тялото на тригера, ще използвамеBEGIN...END
блок: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 ;
-
Когато даден артикул се вмъква в
products
таблица, тригерът ще провериavailability
поле. -
Ако е маркиран с
LOCAL
стойност, продуктът ще бъде наличен само в един магазин. -
Всяка друга стойност ще инструктира тригера да направи продукта достъпен за двата магазина, които създадохме по-рано.
-
-
За да видите
product_availability
тригера в действие, вмъкнете двата записа в таблицата с продукти: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');
-
След това потърсете
products_to_stores
таблица:SELECT * FROM products_to_stores;
Трябва да видите изход, подобен на показания по-долу:
+--------+------------+----------+ | ref_id | product_id | store_id | +--------+------------+----------+ | 1 | 4 | 1 | | 2 | 5 | 1 | | 3 | 5 | 2 | +--------+------------+----------+ 3 rows in set (0.00 sec)
Дефиниране на тригер след актуализиране
Задействане може също да се задейства след UPDATE
събитие. Ще видим как можем да използваме този тип задействане, за да следим промените в цените в нашия магазин с течение на времето.
-
Създайте
product_history_updater
задействате, като изпълните командата по-долу: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);
Това задействане записва промени в
retail_price
на продукт вproducts_price_history
таблица.Забележка За разлика от предишните примери, този тригер има само един израз в тялото на тригера, така че не е необходимо да променяме
DELIMITER
. -
След това опитайте да актуализирате цената на първия продукт, като изпълните командата по-долу:
UPDATE products SET retail_price='36.75' WHERE product_id='1';
-
След това потърсете
products_price_history
таблица, за да видите дали промяната на цената е регистрирана:SELECT * FROM products_price_history;
Ако тригерът работи както се очаква, трябва да получите следния изход:
+------------+---------------------+--------------+ | product_id | price_date | retail_price | +------------+---------------------+--------------+ | 1 | 2020-01-28 11:46:21 | 36.75 | +------------+---------------------+--------------+ 1 row in set (0.00 sec)
Създаване на тригер след изтриване
В някои случаи може да искате да регистрирате операции за изтриване след извършено конкретно действие в базата данни. Можете да постигнете това, като използвате AFTER DELETE
задействане.
-
Създайте нов
product_archiver
задействайте с командата по-долу: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);
Това задейства архивиране на изтритите продукти в отделна таблица с име
archived_products
. Когато даден артикул се изтрие от основнитеproducts
таблица, нашият тригер автоматично ще го регистрира вarchived_products
таблица за бъдещи справки. -
След това изтрийте продукт от
products
таблица и вижте дали тригерът ще бъде извикан:DELETE FROM products WHERE product_id='3';
-
Сега, ако проверите
archived_products
таблица, трябва да видите един запис:SELECT * FROM archived_products;
Изход:
+------------+--------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+--------------+------------+--------------+--------------+ | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+--------------+------------+--------------+--------------+ 1 row in set (0.00 sec)
Изтриване на тригер
Виждали сте различните видове тригери и как те могат да се използват в производствена среда. Понякога може да искате да премахнете тригер от базата данни.
Можете да изтриете задействане, ако не искате да го използвате повече, като използвате синтаксиса по-долу:
DROP TRIGGER IF EXISTS TRIGGER_NAME;
Забележка IF EXISTS
ключовата дума е незадължителен параметр, който изтрива само тригер, ако съществува.
Например, за да изтриете product_archiving
тригер, който дефинирахме по-горе, използвайте командата по-долу:
DROP TRIGGER IF EXISTS product_archiver;
Изход:
Query OK, 0 rows affected (0.00 sec)
Внимание Бъдете внимателни, когато изтривате таблици, свързани с тригери. След като таблица бъде изхвърлена от базата данни MySQL, свързаните тригери също се изтриват автоматично.
Повече информация
Може да пожелаете да се консултирате със следните ресурси за допълнителна информация по тази тема. Въпреки че те са предоставени с надеждата, че ще бъдат полезни, моля, имайте предвид, че не можем да гарантираме за точността или навременността на външно хостваните материали.
- Синтаксис и примери за задействане на MySQL