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 -p
Quindi, 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_database
eseguendo 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
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)
-
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) ...
-
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
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
eretail_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 unLOCAL
valore. Altrimenti, useremo il valore diALL
per indicare un prodotto disponibile in entrambi i negozi (Philadelphia e Galloway).
-
-
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) ...
-
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_id
daiproducts
tabella estore_id
daistores
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)
-
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)
-
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
:OBEFORE
oAFTER
. -
TRIGGER_EVENT
:Devi specificare l'evento del database che richiamerà il trigger:INSERT
,UPDATE
oDELETE
. -
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 ilDELIMITER
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.
-
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 ilcost_price
eretail_price
prima che un record venga inserito neiproducts
tabella, utilizzandoIF...THEN...END IF
dichiarazione. -
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_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. -
Per invocare il
product_name_validator
trigger, 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_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. -
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_availability
grilletto. Poiché abbiamo più righe di codice nel corpo del trigger, utilizzeremo unBEGIN...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à laavailability
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.
-
-
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');
-
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.
-
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 nellaproducts_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
. -
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_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.
-
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 daiproducts
principali tabella, il nostro trigger lo registrerà automaticamente inarchived_products
tabella per riferimento futuro. -
Quindi, elimina un prodotto da
products
tabella e verifica se il trigger verrà richiamato:DELETE FROM products WHERE product_id='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