sql >> Database teknologi >  >> RDS >> Mysql

Arbejde med triggere i en MySQL-database - en vejledning

En trigger er en foruddefineret SQL-kommando, der automatisk udføres, når der sker specifikke handlinger i databasen. Den kan udløses enten før eller efter en INSERT , UPDATE eller DELETE begivenhed.

Triggere bruges hovedsageligt til at vedligeholde softwarelogik i MySQL-serveren, og de har flere fordele:

  • Triggere hjælper med at holde globale operationer centraliseret på ét sted.

  • De reducerer kode på klientsiden og hjælper med at minimere de rundrejser, der foretages til databaseserveren.

  • De hjælper med at gøre applikationer mere skalerbare på tværs af forskellige platforme.

Nogle almindelige use-cases af triggere omfatter revisionslogning, forudberegning af databaseværdier (f.eks. kumulative summer) og håndhævelse af komplekse dataintegritet og valideringsregler.

I denne guide lærer du:

  • Hvordan syntaksen for en trigger er opbygget.

  • Sådan opretter du triggere, der udføres, før andre databasehændelser opstår.

  • Sådan oprettes triggere, der udføres efter andre databasehændelser opstår.

  • Sådan sletter du triggere.

Før du begynder

  1. Hvis du ikke allerede har gjort det, skal du oprette en Linode-konto og Compute Instance. Se vores vejledninger Kom godt i gang med Linode og Oprettelse af en beregningsinstans.

  2. Følg vores guide til konfiguration og sikring af en computerinstans for at opdatere dit system. Du ønsker måske også at indstille tidszonen, konfigurere dit værtsnavn, oprette en begrænset brugerkonto og skærpe SSH-adgang.

  3. En MySQL-server og klient installeret på Linode-serveren. Installationsvejledninger til MySQL er tilgængelige for forskellige distributioner i vores MySQL-sektion.

Forbered databasen

For bedre at forstå, hvordan triggere virker, vil vi oprette en prøvedatabase og tilføje eksempeldata til den. Senere vil vi oprette forskellige triggere på databasen som en proof of concept-øvelse.

  1. Først skal du logge ind på din MySQL-server:

    mysql -u root -p
     

    Indtast derefter root-adgangskoden til din MySQL-server og tryk på Enter for at fortsætte.

  2. Dernæst vil du se en MySQL-prompt, der ligner den, der er vist nedenfor:

    mysql > 
  3. Opret en test_database ved at køre kommandoen nedenfor:

    CREATE DATABASE test_database;
     

    Output:

    Query OK, 1 row affected (0.02 sec) 
  4. Skift til databasen:

    USE test_database;
     

    Output:

    Database changed 
  5. Når databasen er valgt, vil vi oprette nogle tabeller, som vi vil bruge til at demonstrere triggere. Vi begynder med at oprette stores bord. Denne tabel vil indeholde oplysninger om to eksempler på butikker/kontorer, hvor vores hypotetiske virksomhed opererer fra:

    CREATE TABLE stores
    (
    store_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    store_name VARCHAR(50)
    ) ENGINE=InnoDB;
     

    Output:

    Query OK, 0 rows affected (0.07 sec) 
  6. Tilføj derefter to poster til stores tabel ved at køre kommandoerne nedenfor:

    INSERT INTO stores (store_name) VALUES ('Philadelphia');
    INSERT INTO stores (store_name) VALUES ('Galloway');
     

    Efter hver kommando får du nedenstående output:

    Query OK, 1 row affected (0.08 sec)
    ... 
  7. Bekræft registreringerne ved at køre kommandoen nedenfor:

    SELECT * FROM stores;
     

    Output:

    +----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec)
  8. Opret derefter products bord. Bordet vil indeholde forskellige produkter, der tilbydes i butikken:

    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;
     

    Output:

    Query OK, 0 rows affected (0.13 sec) 
    • Hvert produkt vil blive entydigt identificeret med et product_id .

    • Et product_name feltet angiver navnene på emnerne.

    • cost_price og retail_price felter bestemmer henholdsvis købs- og salgsprisen.

    • En availability kolonnen vil definere produkttilgængeligheden i de forskellige butikker. Hvis produktet kun er tilgængeligt i vores lokale butik (Philadelphia), vil vi angive det med en LOCAL værdi. Ellers vil vi bruge værdien af ​​ALL for at betegne et produkt, der er tilgængeligt i begge butikker (Philadelphia og Galloway).

  9. Tilføj eksempeldata til products tabel:

    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');
     

    Du vil få output vist nedenfor efter hver indsæt kommando:

    Query OK, 1 row affected (0.02 sec)
    ... 
  10. Bekræft om produkterne blev indsat ved at køre kommandoen nedenfor:

    SELECT * FROM products;
     

    Output:

    +------------+----------------+------------+--------------+--------------+ | 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. Dernæst vil produkternes tilgængelighed blive knyttet til en anden tabel med navnet products_to_stores . Denne tabel vil kun referere til product_id fra products tabellen og store_id fra stores tabel, hvor varen er tilgængelig.

    Opret products_to_stores tabel ved at køre koden nedenfor:

    CREATE TABLE products_to_stores
    (
    ref_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_id BIGINT,
    store_id BIGINT
    ) ENGINE=InnoDB;
     

    Output:

    Query OK, 0 rows affected (0.14 sec) 
  12. Dernæst vil vi oprette en archived_products bord. Tabellen vil indeholde oplysninger om slettede produkter til fremtidig reference:

    CREATE TABLE archived_products
    (
    product_id BIGINT PRIMARY KEY ,
    product_name VARCHAR(40),
    cost_price DOUBLE,
    retail_price DOUBLE,
    availability VARCHAR(5)
    ) ENGINE=InnoDB;
     

    Output:

    Query OK, 0 rows affected (0.14 sec) 
  13. Til sidst vil vi oprette en products_price_history tabel til sporing af de forskellige priser på hvert produkt over tid:

    CREATE TABLE products_price_history
    (
    product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    price_date DATETIME,
    retail_price DOUBLE
    ) ENGINE=InnoDB;
     

    Output:

    Query OK, 0 rows affected (0.14 sec) 

Når vores databasestruktur er på plads, kan vi nu gå videre og lære den grundlæggende syntaks for en MySQL-databasetrigger for at skabe vores første eksempel.

Triggersyntaks

Som tidligere nævnt udløses triggere automatisk enten før eller efter, at en SQL-kommando køres i databasen. Den grundlæggende syntaks til at oprette triggere er som følger:

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

[TRIGGER BODY];
 
  • TRIGGER_NAME :Hver trigger skal have et unikt navn, og du bør definere det her.

  • TRIGGER_TIME :Enten BEFORE eller AFTER .

  • TRIGGER_EVENT :Du skal angive den databasehændelse, der vil påkalde triggeren:INSERT , UPDATE eller DELETE .

  • TRIGGER BODY :Dette specificerer den faktiske SQL-kommando (eller -kommandoer), som du ønsker skal køres af din trigger.

Hvis en udløserbody har mere end én SQL-sætning, skal du omslutte den i en BEGIN...END blok. Du bliver også nødt til midlertidigt at ændre DELIMITER der signalerer slutningen af ​​triggerkroppen til en ny værdi. Dette sikrer, at udsagn i kroppen ikke fortolkes for tidligt af din MySQL-klient. Et eksempel på dette ser ud som følgende:

DELIMITER &&

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

BEGIN

[TRIGGER BODY]

END &&

DELIMITER ;
 
Bemærk Den sidste linje i dette eksempel ændrer DELIMITER tilbage til standard ; værdi.

Oprettelse af før hændelsesudløsere

I dette afsnit vil vi se på de forskellige typer triggere, der udløses før en databaseoperation. Disse inkluderer BEFORE INSERT , BEFORE UPDATE , og BEFORE DELETE udløser.

Oprettelse af en før indsættelsesudløser

Vi vil oprette vores første BEFORE INSERT udløser. Udløseren sørger for, at udsalgsprisen for et produkt er større end kostprisen, hver gang varer indsættes i products bord. Ellers vil databasebrugeren få en fejl.

  1. Mens du stadig er på mysql > prompt, skal du indtaste kommandoen nedenfor:

    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 ;
     
    • Ovenstående kode definerer triggernavnet (price_validator ), tid (BEFORE ), hændelse (INSERT ), og tabellen (products ) for at blive påvirket.

    • Vores trigger bruger NEW søgeord for at kontrollere cost_price og retail_price før en post indsættes i products tabel ved hjælp af IF...THEN...END IF erklæring.

    • Hvis cost_price er større eller lig med retail price , fortæller vores triggere MySQL om at kaste en tilpasset undtagelse, der instruerer brugeren om at rette fejlen.

  2. For at teste triggeren ovenfor, prøv at indsætte et produkt, der overtræder valideringsreglen:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
     

    Output:

    ERROR 1644 (45000): Retail price must be greater than cost price. 

    Ovenstående indsæt-kommandoer skulle mislykkes, fordi retail_price (144,00) er ikke større end cost_price (145,00).

Oprettelse af en før opdateringsudløser

Dernæst vil vi oprette en BEFORE UPDATE udløser. Denne trigger forhindrer databasebrugere i at redigere et produktnavn, når et produkt er blevet indsat i databasen. Hvis du har flere brugere, der arbejder i databasen, en BEFORE UPDATE trigger kan bruges til at gøre værdier skrivebeskyttet, og dette kan forhindre ondsindede eller skødesløse brugere i at ændre registreringer unødigt.

  1. Opret en ny product_name_validator trigger med kommandoen nedenfor:

    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 ;
     

    Denne trigger sammenligner værdierne for det nye product_name (NEW.product_name ) og det gamle navn, der allerede er i databasen (OLD.product_name ). Hvis der er et misforhold, bliver der kastet en undtagelse.

  2. For at påkalde product_name_validator trigger, kan vi forsøge at opdatere navnet på produktet med ID'et 1 :

    UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
     

    Output:

    ERROR 1644 (45000): Product name is read-only and it can not be changed. 

Definition af en før sletning-trigger

I dette afsnit vil du se, hvordan du kan definere en BEFORE DELETE trigger for at forhindre brugere i at slette specifikke poster fra en tabel.

  1. For at oprette prevent_delete trigger, skal du køre kommandoen nedenfor:

    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 ;
     

    Denne trigger forhindrer produkter markeret med værdien ALL i tilgængelighedskolonnen fra at blive slettet.

  2. Prøv derefter at slette det første produkt fra produkttabellen og se, om triggeren vil blive aktiveret:

    DELETE FROM products WHERE product_id='1';
     

    Output:

    ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores. 

Vi har set på de forskellige triggere, der aktiveres før en databaseoperation. Dernæst vil vi se på de andre typer triggere, der udløses efter databasehændelser.

Oprettelse af efterhændelsestriggere

I et produktionsmiljø ønsker du måske, at nogle triggere udføres automatisk, efter at der opstår en databasehændelse (f.eks. indsættelse af poster i forskellige tabeller). Eksemplerne nedenfor viser, hvordan denne slags triggere kan bruges i vores eksempeldatabase.

Oprettelse af en After Insert Trigger

Dette eksempel opretter en trigger ved navn product_availability der indsætter kortlægningsposter i products_to_stores bord. Denne trigger bruges til at håndhæve forretningslogik; det hjælper især med at definere produkttilgængeligheden for de forskellige butikker.

  1. Kør koden nedenfor for at oprette product_availability udløser. Da vi har flere linjer kode i udløserlegemet, vil vi bruge en BEGIN...END blokere:

    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 ;
     
    • Når en vare indsættes i products tabel, vil udløseren kontrollere availability felt.

    • Hvis det er markeret med LOCAL værdi, vil produktet kun være tilgængeligt i én butik.

    • Enhver anden værdi vil instruere triggeren om at gøre produktet tilgængeligt for de to butikker, vi oprettede tidligere.

  2. For at se product_availability trigger i aktion, indsæt de to poster i produkttabellen:

    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. Forespørg derefter products_to_stores tabel:

    SELECT * FROM products_to_stores;
     

    Du bør se et output svarende til det, der er vist nedenfor:

    +--------+------------+----------+ | ref_id | product_id | store_id | +--------+------------+----------+ | 1 | 4 | 1 | | 2 | 5 | 1 | | 3 | 5 | 2 | +--------+------------+----------+ 3 rows in set (0.00 sec)

Definition af en efter opdateringsudløser

En trigger kan også udløses efter en UPDATE begivenhed. Vi vil se, hvordan vi kan udnytte denne type trigger til at holde styr på prisændringer i vores butik over tid.

  1. Opret en product_history_updater trigger ved at køre kommandoen nedenfor:

    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);
     

    Denne trigger registrerer ændringer af et produkts retail_price i products_price_history tabel.

    Bemærk I modsætning til tidligere eksempler har denne udløser kun én sætning i udløserens krop, så vi behøver ikke at ændre DELIMITER .
  2. Prøv derefter at opdatere prisen på det første produkt ved at køre kommandoen nedenfor:

    UPDATE products SET retail_price='36.75' WHERE product_id='1';
     
  3. Forespørg derefter products_price_history tabel for at se, om prisændringen blev logget:

    SELECT * FROM products_price_history;
     

    Hvis triggeren virkede som forventet, skulle du få nedenstående output:

    +------------+---------------------+--------------+ | product_id | price_date | retail_price | +------------+---------------------+--------------+ | 1 | 2020-01-28 11:46:21 | 36.75 | +------------+---------------------+--------------+ 1 row in set (0.00 sec)

Oprettelse af en After Delete Trigger

I nogle tilfælde vil du måske logge slettehandlinger, efter at en bestemt handling har fundet sted i databasen. Du kan opnå dette ved at bruge AFTER DELETE trigger.

  1. Opret en ny product_archiver trigger med kommandoen nedenfor:

    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);
     

    Denne udløser arkiverer slettede produkter i en separat tabel med navnet archived_products . Når en vare slettes fra de vigtigste products tabel, vil vores trigger automatisk logge den til archived_products tabel til fremtidig reference.

  2. Derefter skal du slette et produkt fra products tabel og se, om udløseren vil blive aktiveret:

    DELETE FROM products WHERE product_id='3';
     
  3. Nu, hvis du tjekker archived_products tabel, bør du se én post:

    SELECT * FROM archived_products;
     

    Output:

    +------------+--------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+--------------+------------+--------------+--------------+ | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+--------------+------------+--------------+--------------+ 1 row in set (0.00 sec)

Sletning af en trigger

Du har set de forskellige typer af triggere, og hvordan de kan bruges i et produktionsmiljø. Nogle gange vil du måske fjerne en trigger fra databasen.

Du kan slette en trigger, hvis du ikke ønsker at bruge den længere ved at bruge syntaksen nedenfor:

DROP TRIGGER IF EXISTS TRIGGER_NAME;
 
Bemærk IF EXISTS søgeord er en valgfri parameter, der kun sletter en trigger, hvis den findes.

For eksempel at slette product_archiving trigger, som vi definerede ovenfor, brug nedenstående kommando:

DROP TRIGGER IF EXISTS product_archiver;
 

Output:

Query OK, 0 rows affected (0.00 sec) 
Forsigtig Vær forsigtig, når du sletter tabeller forbundet med triggere. Når en tabel er slettet fra MySQL-databasen, slettes de relaterede triggere også automatisk.

Flere oplysninger

Du ønsker måske at konsultere følgende ressourcer for yderligere oplysninger om dette emne. Selvom disse leveres i håb om, at de vil være nyttige, bemærk venligst, at vi ikke kan stå inde for nøjagtigheden eller aktualiteten af ​​eksternt hostede materialer.

  • MySQL Trigger-syntaks og eksempler

  1. 10 grunde til at holde fast i MySQL

  2. Gem forespørgselsresultat i en variabel, der bruger i PL/pgSQL

  3. Tips til brug af SQL Server med Salesforce

  4. Understøtter SQLDeveloper eksekvering af scripts?