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 -pVoer 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_databasedoor 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
storestafel. 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
storestabel 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
productstafel. 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_nameveld specificeert de namen van de items. -
De
cost_priceenretail_pricevelden bepalen respectievelijk de koop- en verkoopprijs. -
Een
availabilitykolom bepaalt de productbeschikbaarheid in de verschillende winkels. Als het product alleen verkrijgbaar is in onze lokale winkel (Philadelphia), geven we het aan met eenLOCALwaarde. Anders gebruiken we de waarde vanALLom een product aan te duiden dat in beide winkels (Philadelphia en Galloway) verkrijgbaar is.
-
-
Voeg voorbeeldgegevens toe aan de
productstafel: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_idvan deproductstabel en destore_iduit destorestabel waar het item beschikbaar is.Maak de
products_to_storestabel 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_productstafel. 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_historytabel 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:OfwelBEFOREofAFTER. -
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 deDELIMITERterug 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 DELETEtriggers.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 deproductstafel. 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
NEWtrefwoord om decost_price. te controleren enretail_pricevoordat een record wordt ingevoegd in deproductstabel, met behulp van deIF...THEN...END IFverklaring.Als de
cost_priceis 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 UPDATEtrekker. 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 UPDATEtrigger 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_validatortrigger 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_validatoraan 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_deletete 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
ALLin 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_availabilitydie mapping records invoegt in deproducts_to_storestafel. 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...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 ;
Wanneer een artikel wordt ingevoegd in de
productstabel, de trigger controleert deavailabilityveld.Als het is gemarkeerd met de
LOCALwaarde, 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_availabilityte 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_storestafel: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
UPDATEevenement. 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_updatertrigger 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_pricevan een product in deproducts_price_historytafel.Opmerking In tegenstelling tot eerdere voorbeelden heeft deze trigger slechts één instructie in de hoofdtekst van de trigger, dus we hoeven deDELIMITERniet 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_historytabel 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_archivertrigger 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 belangrijksteproductstabel, zal onze trigger deze automatisch loggen in dearchived_productstabel voor toekomstig gebruik.Verwijder vervolgens een product uit de
productstabel 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 EXISTStrefwoord 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