Een trigger is een vooraf gedefinieerd SQL-commando dat automatisch wordt uitgevoerd wanneer specifieke acties in de database plaatsvinden. Het kan worden afgevuurd voor of na een INSERT
, UPDATE
, of DELETE
evenement.
Triggers worden voornamelijk gebruikt om softwarelogica in de MySQL-server te behouden en ze hebben verschillende voordelen:
-
Triggers helpen de wereldwijde activiteiten op één locatie te centraliseren.
-
Ze verminderen de code aan de clientzijde en helpen de retourvluchten naar de databaseserver te minimaliseren.
-
Ze helpen applicaties schaalbaarder te maken op verschillende platforms.
Enkele veelvoorkomende use-cases van triggers zijn onder meer het loggen van audits, het vooraf berekenen van databasewaarden (bijv. cumulatieve sommen) en het afdwingen van complexe regels voor gegevensintegriteit en validatie.
In deze handleiding leert u:
-
Hoe de syntaxis voor een trigger is gestructureerd.
-
Hoe triggers te maken die worden uitgevoerd voordat andere databasegebeurtenissen plaatsvinden.
-
Hoe triggers te maken die worden uitgevoerd nadat andere databasegebeurtenissen hebben plaatsgevonden.
-
Hoe triggers te verwijderen.
Voordat u begint
-
Als je dit nog niet hebt gedaan, maak dan een Linode-account en Compute Instance aan. Zie onze handleidingen Aan de slag met Linode en Een rekeninstantie maken.
-
Volg onze handleiding voor het instellen en beveiligen van een rekeninstantie om uw systeem bij te werken. Mogelijk wilt u ook de tijdzone instellen, uw hostnaam configureren, een beperkt gebruikersaccount maken en SSH-toegang versterken.
-
Een MySQL-server en client geïnstalleerd op de Linode-server. Installatiehandleidingen voor MySQL zijn beschikbaar voor verschillende distributies in onze MySQL-sectie.
Bereid de database voor
Om beter te begrijpen hoe triggers werken, zullen we een voorbeelddatabase maken en hieraan voorbeeldgegevens toevoegen. Later zullen we verschillende triggers in de database maken als een proof of concept-oefening.
-
Log eerst in op uw MySQL-server:
mysql -u root -p
Voer vervolgens het root-wachtwoord van uw MySQL-server in en druk op Enter om door te gaan.
-
Vervolgens ziet u een MySQL-prompt die lijkt op de onderstaande:
mysql >
-
Maak een
test_database
door het onderstaande commando uit te voeren:CREATE DATABASE test_database;
Uitgang:
Query OK, 1 row affected (0.02 sec)
-
Schakel over naar de database:
USE test_database;
Uitgang:
Database changed
-
Zodra de database is geselecteerd, zullen we enkele tabellen maken die we zullen gebruiken om triggers te demonstreren. We beginnen met het maken van de
stores
tafel. Deze tabel bevat informatie over twee voorbeeldwinkels/kantoren van waaruit ons hypothetische bedrijf opereert:CREATE TABLE stores ( store_id BIGINT PRIMARY KEY AUTO_INCREMENT, store_name VARCHAR(50) ) ENGINE=InnoDB;
Uitgang:
Query OK, 0 rows affected (0.07 sec)
-
Voeg vervolgens twee records toe aan de
stores
tabel door de onderstaande commando's uit te voeren:INSERT INTO stores (store_name) VALUES ('Philadelphia'); INSERT INTO stores (store_name) VALUES ('Galloway');
Na elke opdracht krijgt u de onderstaande uitvoer:
Query OK, 1 row affected (0.08 sec) ...
-
Bevestig de records door de onderstaande opdracht uit te voeren:
SELECT * FROM stores;
Uitgang:
+----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec)
-
Maak vervolgens de
products
tafel. De tafel zal verschillende producten bevatten die in de winkel worden aangeboden: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;
Uitgang:
Query OK, 0 rows affected (0.13 sec)
-
Elk product wordt uniek geïdentificeerd door een
product_id
. -
Een
product_name
veld specificeert de namen van de items. -
De
cost_price
enretail_price
velden bepalen respectievelijk de koop- en verkoopprijs. -
Een
availability
kolom bepaalt de productbeschikbaarheid in de verschillende winkels. Als het product alleen verkrijgbaar is in onze lokale winkel (Philadelphia), geven we het aan met eenLOCAL
waarde. Anders gebruiken we de waarde vanALL
om een product aan te duiden dat in beide winkels (Philadelphia en Galloway) verkrijgbaar is.
-
-
Voeg voorbeeldgegevens toe aan de
products
tafel: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');
U krijgt de onderstaande uitvoer na elk invoegcommando:
Query OK, 1 row affected (0.02 sec) ...
-
Bevestig of de producten zijn ingevoegd door de onderstaande opdracht uit te voeren:
SELECT * FROM products;
Uitgang:
+------------+----------------+------------+--------------+--------------+ | 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)
-
Vervolgens wordt de beschikbaarheid van de producten toegewezen aan een andere tabel met de naam
products_to_stores
. Deze tabel verwijst alleen naar deproduct_id
van deproducts
tabel en destore_id
uit destores
tabel waar het item beschikbaar is.Maak de
products_to_stores
tabel door de onderstaande code uit te voeren:CREATE TABLE products_to_stores ( ref_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, store_id BIGINT ) ENGINE=InnoDB;
Uitgang:
Query OK, 0 rows affected (0.14 sec)
-
Vervolgens maken we een
archived_products
tafel. De tabel bevat informatie over verwijderde producten voor toekomstig gebruik:CREATE TABLE archived_products ( product_id BIGINT PRIMARY KEY , product_name VARCHAR(40), cost_price DOUBLE, retail_price DOUBLE, availability VARCHAR(5) ) ENGINE=InnoDB;
Uitgang:
Query OK, 0 rows affected (0.14 sec)
-
Ten slotte maken we een
products_price_history
tabel voor het volgen van de verschillende prijzen van elk product in de loop van de tijd:CREATE TABLE products_price_history ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, price_date DATETIME, retail_price DOUBLE ) ENGINE=InnoDB;
Uitgang:
Query OK, 0 rows affected (0.14 sec)
Zodra onze databasestructuur op zijn plaats is, kunnen we nu doorgaan en de basissyntaxis van een MySQL-databasetrigger leren om ons eerste voorbeeld te maken.
Triggersyntaxis
Zoals eerder aangegeven, worden triggers automatisch geactiveerd voordat of nadat een SQL-opdracht in de database is uitgevoerd. De basissyntaxis voor het maken van triggers is als volgt:
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
[TRIGGER BODY];
-
TRIGGER_NAME
:Elke trigger moet een unieke naam hebben en u moet deze hier definiëren. -
TRIGGER_TIME
:OfwelBEFORE
ofAFTER
. -
TRIGGER_EVENT
:U moet de databasegebeurtenis specificeren die de trigger zal aanroepen:INSERT
,UPDATE
, ofDELETE
. -
TRIGGER BODY
:Dit specificeert de daadwerkelijke SQL-opdracht (of opdrachten) die u wilt laten uitvoeren door uw trigger.
Als een triggerbody meer dan één SQL-instructie heeft, moet u deze insluiten in een BEGIN...END
blok. U moet ook tijdelijk de DELIMITER
. wijzigen die het einde van het triggerlichaam naar een nieuwe waarde signaleert. Dit zorgt ervoor dat de statements in de body niet voortijdig worden geïnterpreteerd door uw MySQL-client. Een voorbeeld hiervan ziet er als volgt uit:
DELIMITER &&
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
BEGIN
[TRIGGER BODY]
END &&
DELIMITER ;
Opmerking De laatste regel van dit voorbeeld verandert deDELIMITER
terug naar de standaard;
waarde.Creëren voor gebeurtenistriggers
In deze sectie zullen we kijken naar de verschillende soorten triggers die worden geactiveerd voordat een databasebewerking wordt uitgevoerd. Deze omvatten de
BEFORE INSERT
,BEFORE UPDATE
, enBEFORE DELETE
triggers.Een trigger voor invoegen maken
We zullen onze eerste
BEFORE INSERT
. maken trekker. De trigger zorgt ervoor dat de verkoopprijs van een product hoger is dan de kostprijs wanneer artikelen worden ingevoegd in deproducts
tafel. Anders krijgt de databasegebruiker een foutmelding.
Terwijl je nog op de
mysql >
prompt, voer de onderstaande opdracht in: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 ;
De bovenstaande code definieert de triggernaam (
price_validator
), tijd (BEFORE
), gebeurtenis (INSERT
), en de tabel (products
) worden beïnvloed.Onze trigger gebruikt de
NEW
trefwoord om decost_price
. te controleren enretail_price
voordat een record wordt ingevoegd in deproducts
tabel, met behulp van deIF...THEN...END IF
verklaring.Als de
cost_price
is groter dan of gelijk aan deretail price
, onze triggers vertellen MySQL om een aangepaste uitzondering te genereren die de gebruiker opdraagt de fout te herstellen.Om de bovenstaande trigger te testen, probeert u een product in te voegen dat de validatieregel schendt:
INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
Uitgang:
ERROR 1644 (45000): Retail price must be greater than cost price.
De bovenstaande invoegopdrachten zouden moeten mislukken omdat de
retail_price
(144.00) is niet groter dan decost_price
(145,00).Een trigger vóór update maken
Vervolgens maken we een
BEFORE UPDATE
trekker. Deze trigger voorkomt dat databasegebruikers een productnaam kunnen bewerken nadat een product in de database is ingevoegd. Als er meerdere gebruikers in de database werken, verschijnt eenBEFORE UPDATE
trigger kan worden gebruikt om waarden alleen-lezen te maken, en dit kan voorkomen dat kwaadwillende of onzorgvuldige gebruikers records onnodig wijzigen.
Maak een nieuwe
product_name_validator
trigger met het onderstaande commando: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 ;
Deze trigger vergelijkt de waarden van de nieuwe
product_name
(NEW.product_name
) en de oude naam die al in de database staat (OLD.product_name
). Als er een mismatch is, wordt er een uitzondering gegenereerd.Om de
product_name_validator
aan te roepen trigger, kunnen we proberen de naam van het product bij te werken met de ID1
:UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
Uitgang:
ERROR 1644 (45000): Product name is read-only and it can not be changed.
Een trigger voor verwijderen definiëren
In dit gedeelte ziet u hoe u een
BEFORE DELETE
. kunt definiëren trigger om te voorkomen dat gebruikers specifieke records uit een tabel verwijderen.
Om de
prevent_delete
te maken trigger, voer de onderstaande opdracht uit: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 ;
Deze trigger voorkomt dat producten gemarkeerd met de waarde
ALL
in de beschikbaarheidskolom om te worden verwijderd.Probeer vervolgens het eerste product uit de producttabel te verwijderen en kijk of de trigger wordt aangeroepen:
DELETE FROM products WHERE product_id='1';
Uitgang:
ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.
We hebben gekeken naar de verschillende triggers die worden aangeroepen vóór een databasebewerking. Vervolgens zullen we kijken naar de andere soorten triggers die worden geactiveerd na databasegebeurtenissen.
Creëren van after-event-triggers
In een productieomgeving wilt u misschien dat sommige triggers automatisch worden uitgevoerd nadat een databasegebeurtenis heeft plaatsgevonden (bijvoorbeeld door records in verschillende tabellen in te voegen). De onderstaande voorbeelden laten zien hoe dit soort triggers kunnen worden gebruikt in onze voorbeelddatabase.
Een After Insert-trigger maken
In dit voorbeeld wordt een trigger gemaakt met de naam
product_availability
die mapping records invoegt in deproducts_to_stores
tafel. Deze trigger wordt gebruikt om bedrijfslogica af te dwingen; in het bijzonder helpt het bij het bepalen van de productbeschikbaarheid voor de verschillende winkels.
Voer de onderstaande code uit om de
product_availability
. te maken trekker. Omdat we meerdere regels code in de hoofdtekst van de trigger hebben, gebruiken we eenBEGIN...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 ;
Wanneer een artikel wordt ingevoegd in de
products
tabel, de trigger controleert deavailability
veld.Als het is gemarkeerd met de
LOCAL
waarde, wordt het product slechts in één winkel beschikbaar gesteld.Elke andere waarde zal de trigger instrueren om het product beschikbaar te maken voor de twee winkels die we eerder hebben gemaakt.
Om de
product_availability
te zien trigger in actie, voeg de twee records toe aan de producttabel: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');
Vraag vervolgens de
products_to_stores
tafel:SELECT * FROM products_to_stores;
U zou een uitvoer moeten zien die lijkt op die hieronder:
+--------+------------+----------+ | ref_id | product_id | store_id | +--------+------------+----------+ | 1 | 4 | 1 | | 2 | 5 | 1 | | 3 | 5 | 2 | +--------+------------+----------+ 3 rows in set (0.00 sec)
Een after-update-trigger definiëren
Een trigger kan ook worden geactiveerd na een
UPDATE
evenement. We zullen zien hoe we dit type trigger kunnen gebruiken om prijsveranderingen in onze winkel in de loop van de tijd bij te houden.
Maak een
product_history_updater
trigger door de onderstaande opdracht uit te voeren: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);
Deze trigger registreert wijzigingen in de
retail_price
van een product in deproducts_price_history
tafel.Opmerking In tegenstelling tot eerdere voorbeelden heeft deze trigger slechts één instructie in de hoofdtekst van de trigger, dus we hoeven deDELIMITER
niet te wijzigen .Probeer vervolgens de prijs van het eerste product bij te werken door de onderstaande opdracht uit te voeren:
UPDATE products SET retail_price='36.75' WHERE product_id='1';
Vraag vervolgens de
products_price_history
tabel om te zien of de prijswijziging is vastgelegd:SELECT * FROM products_price_history;
Als de trigger werkte zoals verwacht, zou je de onderstaande output moeten krijgen:
+------------+---------------------+--------------+ | product_id | price_date | retail_price | +------------+---------------------+--------------+ | 1 | 2020-01-28 11:46:21 | 36.75 | +------------+---------------------+--------------+ 1 row in set (0.00 sec)
Een trigger voor na het verwijderen maken
In sommige gevallen wilt u wellicht verwijderingsbewerkingen vastleggen nadat een specifieke actie in de database heeft plaatsgevonden. U kunt dit bereiken door de
AFTER DELETE
. te gebruiken trigger.
Maak een nieuwe
product_archiver
trigger met het onderstaande commando: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);
Deze trigger archiveert verwijderde producten in een aparte tabel met de naam
archived_products
. Wanneer een item wordt verwijderd uit de belangrijksteproducts
tabel, zal onze trigger deze automatisch loggen in dearchived_products
tabel voor toekomstig gebruik.Verwijder vervolgens een product uit de
products
tabel en kijk of de trigger wordt aangeroepen:DELETE FROM products WHERE product_id='3';
Als u nu de
archived_products
. aanvinkt tabel, zou u één record moeten zien:SELECT * FROM archived_products;
Uitgang:
+------------+--------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+--------------+------------+--------------+--------------+ | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+--------------+------------+--------------+--------------+ 1 row in set (0.00 sec)
Een trigger verwijderen
Je hebt de verschillende soorten triggers gezien en hoe ze in een productieomgeving kunnen worden gebruikt. Soms wil je misschien een trigger uit de database verwijderen.
U kunt een trigger verwijderen als u deze niet meer wilt gebruiken met behulp van de onderstaande syntaxis:
DROP TRIGGER IF EXISTS TRIGGER_NAME;
Opmerking DeIF EXISTS
trefwoord is een optionele parameter die alleen een trigger verwijdert als deze bestaat.Om bijvoorbeeld de
product_archiving
. te verwijderen trigger die we hierboven hebben gedefinieerd, gebruik het onderstaande commando:DROP TRIGGER IF EXISTS product_archiver;
Uitgang:
Query OK, 0 rows affected (0.00 sec)
Let op Wees voorzichtig bij het verwijderen van tabellen die zijn gekoppeld aan triggers. Zodra een tabel uit de MySQL-database is verwijderd, worden de gerelateerde triggers ook automatisch verwijderd.Meer informatie
U kunt de volgende bronnen raadplegen voor aanvullende informatie over dit onderwerp. Hoewel deze worden verstrekt in de hoop dat ze nuttig zullen zijn, houd er rekening mee dat we niet kunnen instaan voor de nauwkeurigheid of tijdigheid van extern gehost materiaal.
- MySQL-triggersyntaxis en voorbeelden