No universo dos bancos de dados, muitas tarefas são reativas: você insere um pedido e, depois, sua aplicação precisa lembrar de atualizar o estoque. Você altera um salário e, depois, precisa registrar essa mudança em um log. Mas, e se o seu banco de dados pudesse reagir a essas ações sozinho, instantaneamente, como se tivesse vida própria? Essa é a “magia automática” que vamos desvendar neste artigo. Bem-vindo ao mundo dos Triggers (Gatilhos) no MySQL – mecanismos poderosos que “ouvem” suas tabelas e disparam ações sozinhas para garantir a integridade dos dados, automatizar processos e aplicar regras de negócio complexas sem que você precise escrever uma linha de código na sua aplicação para isso.
O que é um Trigger?
Um Trigger é um tipo especial de Stored Procedure que está vinculado a uma tabela e é invocado automaticamente antes ou depois de um evento de modificação de dados (INSERT, UPDATE ou DELETE).
A Analogia Perfeita:
- Uma Stored Procedure é um telefone. Você decide quando ligar (
CALL) para executar uma ação.- Um Trigger é um alarme de incêndio. Você não o ativa. Ele fica “ouvindo” (a tabela) e, se detectar fumaça (um
INSERT,UPDATEouDELETE), ele dispara a ação (o código do trigger) sozinho.
🚨 Quando Usar (e Não Usar) Triggers?
Triggers são incrivelmente úteis, mas também podem ser perigosos, pois executam de forma “invisível” e podem deixar o banco lento se mal escritos.
Use Triggers para:
- Auditoria e Logs: A principal razão. Registrar quem mudou o quê e quando. (Ex: “Salvar em uma tabela
Logtoda vez que o salário de um funcionário for alterado”). - Validação de Regras Complexas: Impor regras de negócio que
CHECK CONSTRAINTSsimples não conseguem. (Ex: “Não permitir que o estoque de um produto fique negativo”). - Sincronização de Dados: Manter dados redundantes (desnormalizados) atualizados. (Ex: “Quando um novo pedido for inserido, atualizar o
total_pedidosna tabela doCliente“).
Evite Triggers para:
- Tarefas que podem ser feitas pela aplicação (seu código Java, Python, PHP).
- Regras de negócio muito complexas que fazem o banco demorar segundos para salvar um dado.
📦 Nosso Ambiente de Teste: A LojaTeste
Para Triggers, precisamos de um cenário diferente da universidade. Vamos usar uma pequena loja. Nosso objetivo será:
- Auditar mudanças de preço.
- Garantir que o estoque não fique negativo.
- Atualizar o estoque automaticamente quando um pedido for feito.
Este script cria nosso ambiente:
SQL
--- CRIA O BANCO DE DADOS (SE NÃO EXISTIR) ---
CREATE DATABASE IF NOT EXISTS LojaTeste;
USE LojaTeste;
--- CRIA A TABELA DE PRODUTOS ---
CREATE TABLE Produtos (
ID_Produto INT PRIMARY KEY AUTO_INCREMENT,
Nome VARCHAR(100) NOT NULL,
Preco DECIMAL(10, 2) NOT NULL,
Estoque INT NOT NULL
) ENGINE=InnoDB;
--- CRIA A TABELA DE PEDIDOS ---
CREATE TABLE Pedidos (
ID_Pedido INT PRIMARY KEY AUTO_INCREMENT,
FK_Produto INT NOT NULL,
Quantidade INT NOT NULL,
Data_Pedido DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (FK_Produto) REFERENCES Produtos(ID_Produto)
) ENGINE=InnoDB;
--- CRIA A TABELA DE LOG (AUDITORIA) ---
-- (Esta tabela será populada APENAS por triggers)
CREATE TABLE Log_Auditoria (
ID_Log INT PRIMARY KEY AUTO_INCREMENT,
Descricao VARCHAR(255) NOT NULL,
DataHora DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- 6. --- INSERE DADOS DE EXEMPLO ---
INSERT INTO Produtos (Nome, Preco, Estoque) VALUES
('Notebook Gamer', 4500.00, 10),
('Mouse Óptico', 150.00, 50),
('Teclado Mecânico', 350.00, 30);
SELECT * FROM Produtos;
A Anatomia de um Trigger no MySQL
Antes de criar, vamos entender as peças:
CREATE TRIGGER <nome_trigger>
<quando> <evento>
ON <nome_tabela>
FOR EACH ROW
BEGIN … END;
<quando>:BEFORE: Dispara antes da ação (INSERT/UPDATE/DELETE) ser executada. Útil para validar ou modificar dados.AFTER: Dispara depois que a ação já foi concluída. Útil para logs e sincronização.
<evento>:INSERT: Quando um novo registro é inserido.UPDATE: Quando um registro existente é modificado.DELETE: Quando um registro é excluído.
FOR EACH ROW: (Obrigatório no MySQL) Significa que o trigger será executado para cada linha afetada pela ação.NEWeOLD: Esta é a parte mais importante! São “variáveis” especiais que o trigger nos dá:
| Evento | OLD (Dados Antigos) | NEW (Dados Novos) |
INSERT | Não existe (é NULL) | Contém a linha que está sendo inserida. |
DELETE | Contém a linha que está sendo excluída. | Não existe (é NULL). |
UPDATE | Contém a linha antes da alteração. | Contém a linha depois da alteração. |
Mão na Massa: Criando Nossos Triggers (MySQL)
Lembre-se de usar o DELIMITER!
Exemplo 1: Auditoria (Usando AFTER UPDATE, OLD e NEW)
Objetivo: Vamos criar um log na tabela Log_Auditoria toda vez que o preço de um produto for alterado.
SQL
-- Mude o delimitador
DELIMITER //
CREATE TRIGGER tr_Audit_Preco_Produto
-- Dispara DEPOIS de um UPDATE...
AFTER UPDATE
-- ...na tabela Produtos
ON Produtos
FOR EACH ROW
BEGIN
-- Verificamos se o preço realmente mudou
-- (OLD.Preco é o preço antigo, NEW.Preco é o preço novo)
IF OLD.Preco <> NEW.Preco THEN
INSERT INTO Log_Auditoria (Descricao)
VALUES (
CONCAT('Preço do produto ID ', NEW.ID_Produto, ' alterado de ',
OLD.Preco, ' para ', NEW.Preco)
);
END IF;
END //
-- Volte o delimitador ao normal
DELIMITER ;
Vamos testar!
Execute um UPDATE normal e veja a “mágica” acontecer.
SQL
-- 1. Aumente o preço do Mouse
UPDATE Produtos SET Preco = 175.00 WHERE ID_Produto = 2;
-- 2. Agora, consulte o LOG!
SELECT * FROM Log_Auditoria;
Resultado: Você verá uma linha no Log_Auditoria que foi inserida automaticamente pelo trigger!
Exemplo 2: Sincronização (Usando AFTER INSERT)
Objetivo: Quando um novo Pedido for inserido, o estoque do Produto correspondente deve diminuir.
SQL
DELIMITER //
CREATE TRIGGER tr_Baixa_Estoque_Pedido
-- Dispara DEPOIS de um INSERT...
AFTER INSERT
-- ...na tabela Pedidos
ON Pedidos
FOR EACH ROW
BEGIN
-- O 'NEW' aqui se refere à linha inserida em Pedidos
UPDATE Produtos
SET Estoque = Estoque - NEW.Quantidade -- (NEW.Quantidade é a quant. do pedido)
WHERE ID_Produto = NEW.FK_Produto; -- (NEW.FK_Produto é o produto do pedido)
END //
DELIMITER ;
Vamos testar!
Primeiro, verifique o estoque do ‘Teclado’ (ID 3), que é 30.
SQL
-- 1. Verifique o estoque atual
SELECT Nome, Estoque FROM Produtos WHERE ID_Produto = 3;
-- 2. Faça um pedido de 5 teclados
INSERT INTO Pedidos (FK_Produto, Quantidade) VALUES (3, 5);
-- 3. Verifique o estoque NOVAMENTE!
SELECT Nome, Estoque FROM Produtos WHERE ID_Produto = 3;
Resultado: O estoque do teclado agora será 25, atualizado automaticamente!
Exemplo 3: Validação (Usando BEFORE INSERT e SIGNAL)
Objetivo: Impedir que um pedido seja inserido se não houver estoque suficiente.
SQL
DELIMITER //
CREATE TRIGGER tr_Valida_Estoque_Antes_Pedido
-- Dispara ANTES de um INSERT...
BEFORE INSERT
-- ...na tabela Pedidos
ON Pedidos
FOR EACH ROW
BEGIN
-- 1. Declara uma variável local para guardar o estoque atual
DECLARE v_EstoqueAtual INT;
-- 2. Busca o estoque do produto que está sendo pedido
SELECT Estoque INTO v_EstoqueAtual
FROM Produtos
WHERE ID_Produto = NEW.FK_Produto;
-- 3. Valida a regra de negócio
IF v_EstoqueAtual < NEW.Quantidade THEN
-- 4. Joga um ERRO e cancela o INSERT
-- (SIGNAL é como se fosse o 'throw new Exception' do SQL)
SIGNAL SQLSTATE '45000' -- '45000' é um estado de erro genérico
SET MESSAGE_TEXT = 'Erro: Estoque insuficiente para este pedido!';
END IF;
END //
DELIMITER ;
Vamos testar!
Temos 10 ‘Notebooks’ (ID 1) em estoque. Vamos tentar comprar 11.
SQL
-- Esta operação vai FALHAR graças ao trigger!
INSERT INTO Pedidos (FK_Produto, Quantidade) VALUES (1, 11);
Resultado: O INSERT será bloqueado e o MySQL retornará o erro: “Erro: Estoque insuficiente para este pedido!”
Como Gerenciar Triggers
- Listar todos os Triggers no banco:SQL
SHOW TRIGGERS; - Excluir um Trigger:SQL
DROP TRIGGER IF EXISTS tr_Valida_Estoque_Antes_Pedido;
Conclusão
Triggers são a automação do banco de dados. Eles agem como guardiões silenciosos que garantem a integridade, auditam mudanças e sincronizam seus dados. Use-os com sabedoria para manter regras de negócio críticas, mas lembre-se: com grande poder, vem uma grande responsabilidade (e a necessidade de testar o impacto na performance!).

