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

Lavorare con i trigger in un database MySQL:un tutorial

Un trigger è un comando SQL predefinito che viene eseguito automaticamente quando si verificano azioni specifiche nel database. Può essere attivato prima o dopo un INSERT , UPDATE o DELETE evento.

I trigger vengono utilizzati principalmente per mantenere la logica del software nel server MySQL e presentano numerosi vantaggi:

  • I trigger aiutano a mantenere le operazioni globali centralizzate in un'unica posizione.

  • Riducono il codice lato client e aiutano a ridurre al minimo i viaggi di andata e ritorno effettuati al server del database.

  • Aiutano a rendere le applicazioni più scalabili su piattaforme diverse.

Alcuni casi d'uso comuni dei trigger includono la registrazione di audit, il precalcolo dei valori del database (ad es. somme cumulative) e l'applicazione di regole complesse di integrità e convalida dei dati.

In questa guida imparerai:

  • Come è strutturata la sintassi di un trigger.

  • Come creare trigger che vengono eseguiti prima che si verifichino altri eventi del database.

  • Come creare trigger che vengono eseguiti dopo che si verificano altri eventi del database.

  • Come eliminare i trigger.

Prima di iniziare

  1. Se non l'hai già fatto, crea un account Linode e un'istanza di calcolo. Consulta le nostre guide Introduzione a Linode e Creazione di un'istanza di calcolo.

  2. Segui la nostra guida alla configurazione e alla protezione di un'istanza di calcolo per aggiornare il tuo sistema. Potresti anche voler impostare il fuso orario, configurare il tuo nome host, creare un account utente limitato e rafforzare l'accesso SSH.

  3. Un server e un client MySQL installati sul server Linode. Le guide all'installazione di MySQL sono disponibili per diverse distribuzioni nella nostra sezione MySQL.

Prepara il database

Per capire meglio come funzionano i trigger, creeremo un database di esempio e vi aggiungeremo dati di esempio. Successivamente, creeremo diversi trigger sul database come esercizio di prova del concetto.

  1. Innanzitutto, accedi al tuo server MySQL:

    mysql -u root -p
    

    Quindi, inserisci la password di root del tuo server MySQL e premi Invio per procedere.

  2. Successivamente, vedrai un prompt MySQL simile a quello mostrato di seguito:

    mysql >
  3. Crea un test_database eseguendo il comando seguente:

    CREATE DATABASE test_database;
    

    Uscita:

    Query OK, 1 row affected (0.02 sec)
  4. Passa al database:

    USE test_database;
    

    Uscita:

    Database changed
  5. Una volta selezionato il database, creeremo alcune tabelle che utilizzeremo per dimostrare i trigger. Inizieremo creando i stores tavolo. Questa tabella conterrà informazioni su due negozi/uffici campione da cui opera la nostra ipotetica attività:

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

    Uscita:

    Query OK, 0 rows affected (0.07 sec)
  6. Quindi, aggiungi due record agli stores tabella eseguendo i comandi seguenti:

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

    Dopo ogni comando, otterrai il seguente output:

    Query OK, 1 row affected (0.08 sec)
    ...
  7. Conferma i record eseguendo il comando seguente:

    SELECT * FROM stores;
    

    Uscita:

    +----------+--------------+
    | store_id | store_name   |
    +----------+--------------+
    |        1 | Philadelphia |
    |        2 | Galloway     |
    +----------+--------------+
    2 rows in set (0.01 sec)
  8. Quindi, crea i products tavolo. Il tavolo conterrà diversi prodotti offerti nel negozio:

    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;
    

    Uscita:

    Query OK, 0 rows affected (0.13 sec)
    • Ogni prodotto sarà identificato in modo univoco da un product_id .

    • Un product_name campo specificherà i nomi degli elementi.

    • Il cost_price e retail_price i campi determineranno rispettivamente il prezzo di acquisto e di vendita.

    • Una availability la colonna definirà la disponibilità del prodotto nei diversi punti vendita. Se il prodotto è disponibile solo nel nostro negozio locale (Filadelfia), lo indicheremo con un LOCAL valore. Altrimenti, useremo il valore di ALL per indicare un prodotto disponibile in entrambi i negozi (Philadelphia e Galloway).

  9. Aggiungi dati di esempio ai products tabella:

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

    Otterrai l'output mostrato di seguito dopo ogni comando di inserimento:

    Query OK, 1 row affected (0.02 sec)
    ...
  10. Conferma se i prodotti sono stati inseriti eseguendo il comando seguente:

    SELECT * FROM products;
    

    Uscita:

    +------------+----------------+------------+--------------+--------------+
    | 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. Successivamente, la disponibilità dei prodotti verrà mappata su un'altra tabella denominata products_to_stores . Questa tabella farà solo riferimento a product_id dai products tabella e store_id dai stores tabella in cui l'articolo è disponibile.

    Crea i products_to_stores tabella eseguendo il codice seguente:

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

    Uscita:

    Query OK, 0 rows affected (0.14 sec)
  12. Successivamente, creeremo un archived_products tavolo. La tabella conterrà informazioni sui prodotti eliminati per riferimento futuro:

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

    Uscita:

    Query OK, 0 rows affected (0.14 sec)
  13. Infine, creeremo una products_price_history tabella per tracciare nel tempo i diversi prezzi di ciascun prodotto:

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

    Uscita:

    Query OK, 0 rows affected (0.14 sec)

Una volta che la nostra struttura del database è a posto, ora possiamo andare avanti e imparare la sintassi di base di un trigger di database MySQL per creare il nostro primo esempio.

Sintassi trigger

Come indicato in precedenza, i trigger vengono attivati ​​automaticamente prima o dopo l'esecuzione di un comando SQL nel database. La sintassi di base per la creazione di trigger è la seguente:

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

[TRIGGER BODY];
  • TRIGGER_NAME :ogni trigger deve avere un nome univoco e dovresti definirlo qui.

  • TRIGGER_TIME :O BEFORE o AFTER .

  • TRIGGER_EVENT :Devi specificare l'evento del database che richiamerà il trigger:INSERT , UPDATE o DELETE .

  • TRIGGER BODY :Specifica il comando (oi comandi) SQL effettivo che desideri venga eseguito dal trigger.

Se un trigger body ha più di un'istruzione SQL, devi racchiuderla in un BEGIN...END bloccare. Inoltre, dovrai modificare temporaneamente il DELIMITER che segnala la fine del corpo del trigger a un nuovo valore. Ciò garantisce che le istruzioni all'interno del corpo non vengano interpretate prematuramente dal client MySQL. Un esempio di questo è simile al seguente:

DELIMITER &&

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

BEGIN

[TRIGGER BODY]

END &&

DELIMITER ;
Nota L'ultima riga di questo esempio cambia il DELIMITER torna al ; valore.

Creazione prima dei trigger di eventi

In questa sezione esamineremo i diversi tipi di trigger che vengono attivati ​​prima di un'operazione di database. Questi includono il BEFORE INSERT , BEFORE UPDATE e BEFORE DELETE trigger.

Creazione di un trigger prima dell'inserimento

Creeremo il nostro primo BEFORE INSERT grilletto. Il trigger farà in modo che il prezzo al dettaglio di un prodotto sia maggiore del prezzo di costo ogni volta che gli articoli vengono inseriti nei products tavolo. In caso contrario, l'utente del database riceverà un errore.

  1. Mentre sei ancora su mysql > prompt, immettere il comando seguente:

    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 ;
    
    • Il codice sopra definisce il nome del trigger (price_validator ), ora (BEFORE ), evento (INSERT ) e la tabella (products ) ad essere interessati.

    • Il nostro trigger utilizza il NEW parola chiave per verificare il cost_price e retail_price prima che un record venga inserito nei products tabella, utilizzando IF...THEN...END IF dichiarazione.

    • Se il cost_price è maggiore o uguale al retail price , i nostri trigger dicono a MySQL di generare un'eccezione personalizzata indicando all'utente di correggere l'errore.

  2. Per testare il trigger sopra, prova a inserire un prodotto che viola la regola di convalida:

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

    Uscita:

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

    I comandi di inserimento precedenti dovrebbero fallire perché retail_price (144.00) non è maggiore del cost_price (145.00).

Creazione di un trigger prima dell'aggiornamento

Successivamente, creeremo un BEFORE UPDATE grilletto. Questo trigger impedirà agli utenti del database di modificare il nome di un prodotto una volta che un prodotto è stato inserito nel database. Se hai più utenti che lavorano nel database, un BEFORE UPDATE trigger può essere utilizzato per rendere i valori di sola lettura e ciò può impedire a utenti malintenzionati o negligenti di modificare i record inutilmente.

  1. Crea un nuovo product_name_validator attivare con il comando seguente:

    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 ;
    

    Questo trigger confronta i valori del nuovo product_name (NEW.product_name ) e il vecchio nome già nel database (OLD.product_name ). In caso di mancata corrispondenza, viene generata un'eccezione.

  2. Per invocare il product_name_validator trigger, possiamo tentare di aggiornare il nome del prodotto con l'ID 1 :

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

    Uscita:

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

Definizione di un trigger prima dell'eliminazione

In questa sezione vedrai come definire un BEFORE DELETE trigger per impedire agli utenti di eliminare record specifici da una tabella.

  1. Per creare il prevent_delete trigger, esegui il comando seguente:

    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 ;
    

    Questo attivatore impedirà i prodotti contrassegnati con un valore di ALL nella colonna disponibilità dall'eliminazione.

  2. Quindi, prova a eliminare il primo prodotto dalla tabella dei prodotti e verifica se verrà richiamato il trigger:

    DELETE FROM products WHERE product_id='1';
    

    Uscita:

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

Abbiamo esaminato i diversi trigger che vengono invocati prima di un'operazione di database. Successivamente, esamineremo gli altri tipi di trigger che vengono attivati ​​dopo gli eventi del database.

Creazione di trigger dopo l'evento

In un ambiente di produzione, è possibile che alcuni trigger vengano eseguiti automaticamente dopo che si è verificato un evento del database (ad esempio, l'inserimento di record in tabelle diverse). Gli esempi seguenti dimostrano come questi tipi di trigger possono essere utilizzati nel nostro database di esempio.

Creazione di un trigger dopo l'inserimento

Questo esempio crea un trigger denominato product_availability che inserisce i record di mappatura in products_to_stores tavolo. Questo trigger viene utilizzato per imporre la logica aziendale; in particolare, aiuta a definire la disponibilità del prodotto per i diversi punti vendita.

  1. Esegui il codice seguente per creare il product_availability grilletto. Poiché abbiamo più righe di codice nel corpo del trigger, utilizzeremo un BEGIN...END blocco:

    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 ;
    
    • Quando un articolo viene inserito nei products tabella, il trigger verificherà la availability campo.

    • Se è contrassegnato con il LOCAL valore, il prodotto sarà reso disponibile in un solo negozio.

    • Qualsiasi altro valore indicherà al trigger di rendere disponibile il prodotto ai due negozi che abbiamo creato in precedenza.

  2. Per vedere il product_availability trigger in azione, inserisci i due record nella tabella prodotti:

    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. Quindi, esegui una query su products_to_stores tabella:

    SELECT * FROM products_to_stores;
    

    Dovresti vedere un output simile a quello mostrato di seguito:

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

Definizione di un trigger dopo l'aggiornamento

Un trigger può essere attivato anche dopo un UPDATE evento. Vedremo come possiamo sfruttare questo tipo di trigger per tenere traccia delle variazioni di prezzo nel nostro negozio nel tempo.

  1. Crea un product_history_updater trigger eseguendo il comando seguente:

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

    Questo attivatore registra le modifiche al retail_price di un prodotto nella products_price_history tabella.

    Nota A differenza degli esempi precedenti, questo trigger ha solo un'istruzione nel corpo del trigger, quindi non è necessario modificare il DELIMITER .
  2. Quindi, prova ad aggiornare il prezzo del primo prodotto eseguendo il comando seguente:

    UPDATE products SET retail_price='36.75' WHERE product_id='1';
    
  3. Quindi, esegui una query su products_price_history tabella per vedere se la variazione di prezzo è stata registrata:

    SELECT * FROM products_price_history;
    

    Se il trigger ha funzionato come previsto, dovresti ottenere l'output seguente:

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

Creazione di un trigger dopo l'eliminazione

In alcuni casi, potresti voler registrare le operazioni di eliminazione dopo che si è verificata un'azione specifica nel database. Puoi ottenere ciò utilizzando il AFTER DELETE trigger.

  1. Crea un nuovo product_archiver attivare con il comando seguente:

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

    Questo trigger archivia i prodotti eliminati in una tabella separata denominata archived_products . Quando un articolo viene eliminato dai products principali tabella, il nostro trigger lo registrerà automaticamente in archived_products tabella per riferimento futuro.

  2. Quindi, elimina un prodotto da products tabella e verifica se il trigger verrà richiamato:

    DELETE FROM products WHERE product_id='3';
    
  3. Ora, se controlli archived_products tabella, dovresti vedere un record:

    SELECT * FROM archived_products;
    

    Uscita:

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

Eliminazione di un trigger

Hai visto i diversi tipi di trigger e come possono essere utilizzati in un ambiente di produzione. A volte, potresti voler rimuovere un trigger dal database.

Puoi eliminare un trigger se non vuoi più usarlo utilizzando la sintassi seguente:

DROP TRIGGER IF EXISTS TRIGGER_NAME;
Nota Il IF EXISTS la parola chiave è un parametro facoltativo che elimina un trigger solo se esiste.

Ad esempio, per eliminare il product_archiving trigger che abbiamo definito sopra, usa il comando seguente:

DROP TRIGGER IF EXISTS product_archiver;

Uscita:

Query OK, 0 rows affected (0.00 sec)
Attenzione Prestare attenzione quando si eliminano le tabelle associate ai trigger. Una volta eliminata una tabella dal database MySQL, anche i relativi trigger vengono automaticamente eliminati.

Maggiori informazioni

Si consiglia di consultare le seguenti risorse per ulteriori informazioni su questo argomento. Sebbene questi siano forniti nella speranza che possano essere utili, tieni presente che non possiamo garantire l'accuratezza o la tempestività dei materiali ospitati esternamente.

  • Sintassi ed esempi del trigger MySQL