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
-
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.
-
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.
-
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.
-
Innanzitutto, accedi al tuo server MySQL:
mysql -u root -pQuindi, inserisci la password di root del tuo server MySQL e premi Invio per procedere.
-
Successivamente, vedrai un prompt MySQL simile a quello mostrato di seguito:
mysql > -
Crea un
test_databaseeseguendo il comando seguente:CREATE DATABASE test_database;Uscita:
Query OK, 1 row affected (0.02 sec) -
Passa al database:
USE test_database;Uscita:
Database changed -
Una volta selezionato il database, creeremo alcune tabelle che utilizzeremo per dimostrare i trigger. Inizieremo creando i
storestavolo. 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) -
Quindi, aggiungi due record agli
storestabella 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) ... -
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) -
Quindi, crea i
productstavolo. 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_namecampo specificherà i nomi degli elementi. -
Il
cost_priceeretail_pricei campi determineranno rispettivamente il prezzo di acquisto e di vendita. -
Una
availabilityla colonna definirà la disponibilità del prodotto nei diversi punti vendita. Se il prodotto è disponibile solo nel nostro negozio locale (Filadelfia), lo indicheremo con unLOCALvalore. Altrimenti, useremo il valore diALLper indicare un prodotto disponibile in entrambi i negozi (Philadelphia e Galloway).
-
-
Aggiungi dati di esempio ai
productstabella: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) ... -
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) -
Successivamente, la disponibilità dei prodotti verrà mappata su un'altra tabella denominata
products_to_stores. Questa tabella farà solo riferimento aproduct_iddaiproductstabella estore_iddaistorestabella in cui l'articolo è disponibile.Crea i
products_to_storestabella 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) -
Successivamente, creeremo un
archived_productstavolo. 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) -
Infine, creeremo una
products_price_historytabella 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:OBEFOREoAFTER. -
TRIGGER_EVENT:Devi specificare l'evento del database che richiamerà il trigger:INSERT,UPDATEoDELETE. -
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 ilDELIMITERtorna 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.
-
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
NEWparola chiave per verificare ilcost_priceeretail_priceprima che un record venga inserito neiproductstabella, utilizzandoIF...THEN...END IFdichiarazione. -
Se il
cost_priceè maggiore o uguale alretail price, i nostri trigger dicono a MySQL di generare un'eccezione personalizzata indicando all'utente di correggere l'errore.
-
-
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 delcost_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.
-
Crea un nuovo
product_name_validatorattivare 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. -
Per invocare il
product_name_validatortrigger, possiamo tentare di aggiornare il nome del prodotto con l'ID1: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.
-
Per creare il
prevent_deletetrigger, 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
ALLnella colonna disponibilità dall'eliminazione. -
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.
-
Esegui il codice seguente per creare il
product_availabilitygrilletto. Poiché abbiamo più righe di codice nel corpo del trigger, utilizzeremo unBEGIN...ENDblocco: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
productstabella, il trigger verificherà laavailabilitycampo. -
Se è contrassegnato con il
LOCALvalore, 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.
-
-
Per vedere il
product_availabilitytrigger 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'); -
Quindi, esegui una query su
products_to_storestabella: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.
-
Crea un
product_history_updatertrigger 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_pricedi un prodotto nellaproducts_price_historytabella.Nota A differenza degli esempi precedenti, questo trigger ha solo un'istruzione nel corpo del trigger, quindi non è necessario modificare il
DELIMITER. -
Quindi, prova ad aggiornare il prezzo del primo prodotto eseguendo il comando seguente:
UPDATE products SET retail_price='36.75' WHERE product_id='1'; -
Quindi, esegui una query su
products_price_historytabella 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.
-
Crea un nuovo
product_archiverattivare 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 daiproductsprincipali tabella, il nostro trigger lo registrerà automaticamente inarchived_productstabella per riferimento futuro. -
Quindi, elimina un prodotto da
productstabella e verifica se il trigger verrà richiamato:DELETE FROM products WHERE product_id='3'; -
Ora, se controlli
archived_productstabella, 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