Un gatillo es un comando SQL predefinido que se ejecuta automáticamente cuando ocurren acciones específicas en la base de datos. Se puede disparar antes o después de un INSERT
, UPDATE
o DELETE
evento.
Los disparadores se utilizan principalmente para mantener la lógica del software en el servidor MySQL y tienen varios beneficios:
-
Los disparadores ayudan a mantener las operaciones globales centralizadas en un solo lugar.
-
Reducen el código del lado del cliente y ayudan a minimizar los viajes de ida y vuelta realizados al servidor de la base de datos.
-
Ayudan a que las aplicaciones sean más escalables en diferentes plataformas.
Algunos casos de uso comunes de disparadores incluyen el registro de auditoría, el cálculo previo de los valores de la base de datos (por ejemplo, sumas acumulativas) y la aplicación de reglas de validación e integridad de datos complejas.
En esta guía, aprenderá:
-
Cómo está estructurada la sintaxis de un disparador.
-
Cómo crear disparadores que se ejecuten antes de que ocurran otros eventos de la base de datos.
-
Cómo crear activadores que se ejecuten después de que ocurran otros eventos de la base de datos.
-
Cómo eliminar disparadores.
Antes de comenzar
-
Si aún no lo ha hecho, cree una cuenta de Linode y una instancia de cómputo. Consulte nuestras guías Introducción a Linode y Creación de una instancia informática.
-
Siga nuestra guía de configuración y protección de una instancia informática para actualizar su sistema. También puede establecer la zona horaria, configurar su nombre de host, crear una cuenta de usuario limitada y fortalecer el acceso SSH.
-
Un servidor MySQL y un cliente instalado en el servidor Linode. Las guías de instalación de MySQL están disponibles para diferentes distribuciones en nuestra sección MySQL.
Preparar la base de datos
Para comprender mejor cómo funcionan los disparadores, crearemos una base de datos de muestra y le agregaremos datos de muestra. Más adelante, crearemos diferentes activadores en la base de datos como ejercicio de prueba de concepto.
-
Primero, inicie sesión en su servidor MySQL:
mysql -u root -p
Luego, ingrese la contraseña raíz de su servidor MySQL y presione Enter para proceder.
-
A continuación, verá un indicador de MySQL similar al que se muestra a continuación:
mysql >
-
Crear una
test_database
ejecutando el siguiente comando:CREATE DATABASE test_database;
Salida:
Query OK, 1 row affected (0.02 sec)
-
Cambiar a la base de datos:
USE test_database;
Salida:
Database changed
-
Una vez seleccionada la base de datos, crearemos algunas tablas que usaremos para demostrar los disparadores. Comenzaremos creando las
stores
mesa. Esta tabla contendrá información sobre dos tiendas/oficinas de muestra desde donde opera nuestro negocio hipotético:CREATE TABLE stores ( store_id BIGINT PRIMARY KEY AUTO_INCREMENT, store_name VARCHAR(50) ) ENGINE=InnoDB;
Salida:
Query OK, 0 rows affected (0.07 sec)
-
A continuación, agregue dos registros a las
stores
table ejecutando los siguientes comandos:INSERT INTO stores (store_name) VALUES ('Philadelphia'); INSERT INTO stores (store_name) VALUES ('Galloway');
Después de cada comando, obtendrá el siguiente resultado:
Query OK, 1 row affected (0.08 sec) ...
-
Confirme los registros ejecutando el siguiente comando:
SELECT * FROM stores;
Salida:
+----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec)
-
A continuación, cree los
products
mesa. La mesa albergará diferentes productos que se ofrecen en la tienda: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;
Salida:
Query OK, 0 rows affected (0.13 sec)
-
Cada producto se identificará de forma única mediante un
product_id
. -
Un
product_name
campo especificará los nombres de los elementos. -
El
cost_price
yretail_price
campos determinarán el precio de compra y venta respectivamente. -
Una
availability
La columna definirá la disponibilidad del producto en las diferentes tiendas. Si el producto solo está disponible en nuestra tienda local (Filadelfia), lo indicaremos con unLOCAL
valor. De lo contrario, usaremos el valor deALL
para indicar un producto que está disponible en ambas tiendas (Philadelphia y Galloway).
-
-
Agregar datos de muestra a los
products
tabla: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');
Obtendrá el resultado que se muestra a continuación después de cada comando de inserción:
Query OK, 1 row affected (0.02 sec) ...
-
Confirme si los productos se insertaron ejecutando el siguiente comando:
SELECT * FROM products;
Salida:
+------------+----------------+------------+--------------+--------------+ | 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)
-
A continuación, la disponibilidad de los productos se asignará a otra tabla llamada
products_to_stores
. Esta tabla solo hará referencia alproduct_id
de losproducts
tabla y elstore_id
de lasstores
tabla donde está disponible el artículo.Crea los
products_to_stores
tabla ejecutando el siguiente código:CREATE TABLE products_to_stores ( ref_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, store_id BIGINT ) ENGINE=InnoDB;
Salida:
Query OK, 0 rows affected (0.14 sec)
-
A continuación, crearemos un
archived_products
mesa. La tabla contendrá información sobre los productos eliminados para referencia futura:CREATE TABLE archived_products ( product_id BIGINT PRIMARY KEY , product_name VARCHAR(40), cost_price DOUBLE, retail_price DOUBLE, availability VARCHAR(5) ) ENGINE=InnoDB;
Salida:
Query OK, 0 rows affected (0.14 sec)
-
Por último, crearemos un
products_price_history
tabla para el seguimiento de los diferentes precios de cada producto a lo largo del tiempo:CREATE TABLE products_price_history ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, price_date DATETIME, retail_price DOUBLE ) ENGINE=InnoDB;
Salida:
Query OK, 0 rows affected (0.14 sec)
Una vez que nuestra estructura de base de datos esté en su lugar, ahora podemos continuar y aprender la sintaxis básica de un disparador de base de datos MySQL para crear nuestra primera muestra.
Sintaxis de activación
Como se indicó anteriormente, los activadores se activan automáticamente antes o después de ejecutar un comando SQL en la base de datos. La sintaxis básica para crear disparadores es la siguiente:
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
[TRIGGER BODY];
-
TRIGGER_NAME
:Cada activador debe tener un nombre único y debe definirlo aquí. -
TRIGGER_TIME
:CualquieraBEFORE
oAFTER
. -
TRIGGER_EVENT
:debe especificar el evento de la base de datos que invocará el disparador:INSERT
,UPDATE
oDELETE
. -
TRIGGER BODY
:Esto especifica el comando SQL real (o los comandos) que desea que su disparador ejecute.
Si el cuerpo de un disparador tiene más de una instrucción SQL, debe encerrarlo dentro de un BEGIN...END
cuadra. Además, deberá cambiar temporalmente el DELIMITER
que señala el final del cuerpo del disparador a un nuevo valor. Esto asegura que las declaraciones dentro del cuerpo no sean interpretadas prematuramente por su cliente MySQL. Un ejemplo de esto se parece a lo siguiente:
DELIMITER &&
CREATE TRIGGER TRIGGER_NAME
TRIGGER_TIME TRIGGER_EVENT
ON TABLE_NAME FOR EACH ROW
BEGIN
[TRIGGER BODY]
END &&
DELIMITER ;
Nota La última línea de este ejemplo cambia elDELIMITER
volver al predeterminado;
valor.
Crear antes de activadores de eventos
En esta sección, veremos los diferentes tipos de activadores que se activan antes de una operación de base de datos. Estos incluyen el BEFORE INSERT
, BEFORE UPDATE
y BEFORE DELETE
disparadores.
Creación de un disparador antes de insertar
Crearemos nuestro primer BEFORE INSERT
generar. El activador se asegurará de que el precio minorista de un producto sea mayor que el precio de costo cada vez que se inserten elementos en los products
. mesa. De lo contrario, el usuario de la base de datos obtendrá un error.
-
Mientras todavía está en
mysql >
indicador, ingrese el siguiente comando: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 ;
-
El código anterior define el nombre del disparador (
price_validator
), hora (BEFORE
), evento (INSERT
), y la tabla (products
) para verse afectado. -
Nuestro disparador usa el
NEW
palabra clave para comprobar elcost_price
yretail_price
antes de que se inserte un registro en losproducts
tabla, usando elIF...THEN...END IF
declaración. -
Si el
cost_price
es mayor o igual alretail price
, nuestros disparadores le dicen a MySQL que arroje una excepción personalizada que indique al usuario que rectifique el error.
-
-
Para probar el disparador anterior, intente insertar un producto que viole la regla de validación:
INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
Salida:
ERROR 1644 (45000): Retail price must be greater than cost price.
Los comandos de inserción anteriores deberían fallar porque el
retail_price
(144,00) no es mayor que elcost_price
(145,00).
Creación de un disparador antes de la actualización
A continuación, crearemos un BEFORE UPDATE
generar. Este activador evitará que los usuarios de la base de datos editen el nombre de un producto una vez que se haya insertado un producto en la base de datos. Si tiene varios usuarios trabajando en la base de datos, BEFORE UPDATE
El disparador se puede usar para hacer que los valores sean de solo lectura, y esto puede evitar que los usuarios maliciosos o descuidados modifiquen los registros innecesariamente.
-
Cree un nuevo
product_name_validator
dispara con el siguiente comando: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 ;
Este disparador compara los valores del nuevo
product_name
(NEW.product_name
) y el nombre antiguo que ya está en la base de datos (OLD.product_name
). Si no coincide, se lanza una excepción. -
Para invocar el
product_name_validator
activador, podemos intentar actualizar el nombre del producto con el ID1
:UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
Salida:
ERROR 1644 (45000): Product name is read-only and it can not be changed.
Definir un activador antes de eliminar
En esta sección, verá cómo puede definir un BEFORE DELETE
activador para evitar que los usuarios eliminen registros específicos de una tabla.
-
Para crear el
prevent_delete
desencadenar, ejecute el siguiente comando: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 ;
Este disparador evitará que los productos marcados con un valor de
ALL
en la columna de disponibilidad para que no se eliminen. -
A continuación, intente eliminar el primer producto de la tabla de productos y vea si se invocará el activador:
DELETE FROM products WHERE product_id='1';
Salida:
ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.
Hemos analizado los diferentes disparadores que se invocan antes de una operación de base de datos. A continuación, veremos los otros tipos de activadores que se activan después de los eventos de la base de datos.
Creación de desencadenantes posteriores al evento
En un entorno de producción, es posible que desee que algunos disparadores se ejecuten automáticamente después de que ocurra un evento de la base de datos (por ejemplo, insertar registros en diferentes tablas). Los ejemplos a continuación demuestran cómo se pueden usar estos tipos de disparadores en nuestra base de datos de muestra.
Crear un disparador después de insertar
Este ejemplo crea un disparador llamado product_availability
que inserta registros de mapeo en el products_to_stores
mesa. Este activador se utiliza para aplicar la lógica empresarial; en particular, ayuda a definir la disponibilidad del producto para las diferentes tiendas.
-
Ejecute el siguiente código para crear el
product_availability
generar. Dado que tenemos varias líneas de código en el cuerpo del disparador, usaremos unBEGIN...END
bloque: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 ;
-
Cuando se inserta un elemento en los
products
tabla, el activador comprobará laavailability
campo. -
Si está marcado con el
LOCAL
valor, el producto estará disponible en una sola tienda. -
Cualquier otro valor indicará al disparador que haga que el producto esté disponible para las dos tiendas que creamos anteriormente.
-
-
Para ver la
product_availability
activador en acción, inserte los dos registros en la tabla de productos: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');
-
Luego, consulta el
products_to_stores
tabla:SELECT * FROM products_to_stores;
Debería ver un resultado similar al que se muestra a continuación:
+--------+------------+----------+ | ref_id | product_id | store_id | +--------+------------+----------+ | 1 | 4 | 1 | | 2 | 5 | 1 | | 3 | 5 | 2 | +--------+------------+----------+ 3 rows in set (0.00 sec)
Definir un disparador posterior a la actualización
También se puede activar un disparador después de una UPDATE
evento. Veremos cómo podemos aprovechar este tipo de activador para realizar un seguimiento de los cambios de precios en nuestra tienda a lo largo del tiempo.
-
Crear un
product_history_updater
desencadenar ejecutando el siguiente comando: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);
Este activador registra los cambios en el
retail_price
de un producto. en elproducts_price_history
mesa.Nota A diferencia de los ejemplos anteriores, este disparador solo tiene una declaración en el cuerpo del disparador, por lo que no necesitamos cambiar el
DELIMITER
. -
Luego, intente actualizar el precio del primer producto ejecutando el siguiente comando:
UPDATE products SET retail_price='36.75' WHERE product_id='1';
-
A continuación, consulta el
products_price_history
tabla para ver si se registró el cambio de precio:SELECT * FROM products_price_history;
Si el activador funcionó como se esperaba, debería obtener el siguiente resultado:
+------------+---------------------+--------------+ | product_id | price_date | retail_price | +------------+---------------------+--------------+ | 1 | 2020-01-28 11:46:21 | 36.75 | +------------+---------------------+--------------+ 1 row in set (0.00 sec)
Creación de un activador posterior a la eliminación
En algunos casos, es posible que desee registrar operaciones de eliminación después de que se haya producido una acción específica en la base de datos. Puede lograr esto usando AFTER DELETE
disparador.
-
Cree un nuevo
product_archiver
dispara con el siguiente comando: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);
Este disparador archiva los productos eliminados en una tabla separada llamada
archived_products
. Cuando se elimina un artículo de losproducts
principales tabla, nuestro activador lo registrará automáticamente enarchived_products
tabla para referencia futura. -
A continuación, elimine un producto de los
products
tabla y vea si se invocará el disparador:DELETE FROM products WHERE product_id='3';
-
Ahora, si revisa los
archived_products
tabla, debería ver un registro:SELECT * FROM archived_products;
Salida:
+------------+--------------+------------+--------------+--------------+ | product_id | product_name | cost_price | retail_price | availability | +------------+--------------+------------+--------------+--------------+ | 3 | SMART WATCH | 189.6 | 225.3 | LOCAL | +------------+--------------+------------+--------------+--------------+ 1 row in set (0.00 sec)
Eliminación de un activador
Ha visto los diferentes tipos de activadores y cómo se pueden utilizar en un entorno de producción. A veces, es posible que desee eliminar un disparador de la base de datos.
Puede eliminar un disparador si ya no desea usarlo usando la siguiente sintaxis:
DROP TRIGGER IF EXISTS TRIGGER_NAME;
Nota El IF EXISTS
La palabra clave es un parámetro opcional que solo elimina un disparador si existe.
Por ejemplo, para eliminar el product_archiving
disparador que definimos arriba, use el siguiente comando:
DROP TRIGGER IF EXISTS product_archiver;
Salida:
Query OK, 0 rows affected (0.00 sec)
Precaución Tenga cuidado al eliminar tablas asociadas con disparadores. Una vez que se elimina una tabla de la base de datos MySQL, los activadores relacionados también se eliminan automáticamente.
Más información
Es posible que desee consultar los siguientes recursos para obtener información adicional sobre este tema. Si bien estos se proporcionan con la esperanza de que sean útiles, tenga en cuenta que no podemos garantizar la precisión o la puntualidad de los materiales alojados externamente.
- Sintaxis y ejemplos de activación de MySQL