Triggers e Eventos
Triggers e Eventos
Analogia do Mundo Real
Imagine um sistema de casa inteligente:
- Trigger é como "quando alguém toca a campainha, acender automaticamente a luz da varanda" — quando um determinado evento ocorre, uma ação predefinida é executada automaticamente.
- Agendador de eventos é como "todos os dias às 7h, abrir automaticamente as cortinas" — tarefas são executadas periodicamente de acordo com um cronograma de tempo.
Conceitos Fundamentais
O que é uma Trigger
Uma Trigger é um objeto de banco de dados associado a uma tabela que é executado automaticamente quando um evento específico ocorre nessa tabela:
- É disparada antes ou após a inserção (INSERT), atualização (UPDATE) ou exclusão (DELETE) de dados
- Pode acessar os dados modificados (referências NEW e OLD)
- Usada para implementar regras de negócios complexas, logs de auditoria e restrições de integridade de dados
Momento da Trigger: BEFORE vs AFTER
| Momento | Descrição | Uso Típico |
|---|---|---|
| BEFORE | Dispara antes da execução da operação | Validação de dados, modificação automática de valores |
| AFTER | Dispara após a execução da operação | Logs de auditoria, atualizações em cascata |
Tipos de Eventos da Trigger
- INSERT: Dispara quando um novo registro é inserido
- UPDATE: Dispara quando um registro é atualizado
- DELETE: Dispara quando um registro é excluído
Referências NEW e OLD
Você pode acessar os dados sendo operados dentro de uma trigger:
| Evento | NEW | OLD |
|---|---|---|
| INSERT | A linha recém-inserida | Não disponível |
| UPDATE | O valor após a atualização | O valor antes da atualização |
| DELETE | Não disponível | A linha excluída |
-- Exemplo SQLite: acessando NEW e OLD
-- NEW.nome_coluna: referencia os novos dados
-- OLD.nome_coluna: referencia os dados antigos
Casos de Uso Típicos de Triggers
- Logs de auditoria: Registrar quem modificou quais dados e quando
- Atualizações em cascata: Atualizar automaticamente dados em tabelas relacionadas
- Validação de dados: Realizar validação complexa de regras de negócios antes de dados serem gravados
- Cálculo automático: Calcular automaticamente valores de campos derivados
- Manutenção de dados redundantes: Sincronizar atualizações em tabelas de resumo ou cache
Conhecimento Estendido: Agendador de Eventos em Outros Bancos de Dados
O agendador de eventos permite executar tarefas automaticamente em um cronograma de tempo:
-- Exemplo de agendador de eventos MySQL
-- Habilitar o agendador de eventos
SET GLOBAL event_scheduler = ON;
-- Criar um evento agendado: limpar dados expirados diariamente à meia-noite
CREATE EVENT cleanup_expired_orders
ON SCHEDULE EVERY 1 DAY
STARTS '2024-01-01 00:00:00'
DO
DELETE FROM orders
WHERE status = 'expired'
AND created_at < DATE_SUB(NOW(), INTERVAL 90 DAY);
-- Criar um evento único
CREATE EVENT one_time_report
ON SCHEDULE AT '2024-12-31 23:59:59'
DO
INSERT INTO annual_report (year, total_sales)
SELECT YEAR(NOW()), SUM(amount) FROM orders WHERE YEAR(created_at) = YEAR(NOW());
-- Ver todos os eventos
SHOW EVENTS;
-- Desabilitar um evento
ALTER EVENT cleanup_expired_orders DISABLE;
-- Excluir um evento
DROP EVENT IF EXISTS cleanup_expired_orders;
Sintaxe Básica
Sintaxe de Trigger SQLite
SQLite suporta triggers com a seguinte sintaxe:
-- Sintaxe básica de criação de trigger
CREATE TRIGGER nome_trigger
{BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON nome_tabela
[FOR EACH ROW]
[WHEN condição]
BEGIN
-- Lógica da trigger
END;
Sintaxe de Trigger MySQL
-- Sintaxe de trigger MySQL
DELIMITER //
CREATE TRIGGER nome_trigger
{BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON nome_tabela
FOR EACH ROW
BEGIN
-- Lógica da trigger
-- Use NEW e OLD para referenciar dados
END //
DELIMITER ;
Sintaxe de Trigger PostgreSQL
-- PostgreSQL requer criar uma função de trigger primeiro
CREATE OR REPLACE FUNCTION nome_funcao_trigger()
RETURNS TRIGGER AS $$
BEGIN
-- Lógica da trigger
RETURN NEW; -- ou RETURN OLD
END;
$$ LANGUAGE plpgsql;
-- Depois criar a trigger
CREATE TRIGGER nome_trigger
{BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON nome_tabela
FOR EACH ROW
EXECUTE FUNCTION nome_funcao_trigger();
Exemplos
Exemplo: Criando uma Trigger de Log de Auditoria (Dificuldade ⭐⭐)
Crie uma trigger que registre automaticamente o histórico de modificações de salários de funcionários.
-- Versão SQLite
-- Primeiro criar a tabela de log de auditoria
CREATE TABLE IF NOT EXISTS salary_audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
employee_id INTEGER,
old_salary REAL,
new_salary REAL,
changed_by TEXT,
changed_at TEXT DEFAULT (datetime('now', 'localtime')),
action TEXT
);
-- Criar trigger: registrar atualizações de salário
CREATE TRIGGER audit_salary_update
AFTER UPDATE ON employees
FOR EACH ROW
WHEN OLD.salary != NEW.salary
BEGIN
INSERT INTO salary_audit_log (
employee_id,
old_salary,
new_salary,
changed_by,
action
)
VALUES (
NEW.id,
OLD.salary,
NEW.salary,
'system', -- Na prática, você pode usar o usuário atual
'UPDATE'
);
END;
-- Testar a trigger
UPDATE employees SET salary = 12000 WHERE id = 1;
-- Ver o log de auditoria
SELECT * FROM salary_audit_log;
Exemplo: Trigger BEFORE INSERT para Preenchimento Automático de Dados (Dificuldade ⭐⭐)
Crie uma trigger que defina automaticamente a data do pedido e o status inicial ao inserir um pedido.
-- Criar tabela de pedidos
CREATE TABLE IF NOT EXISTS orders_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_name TEXT NOT NULL,
product_id INTEGER,
quantity INTEGER DEFAULT 1,
order_date TEXT,
status TEXT DEFAULT 'pending',
created_at TEXT
);
-- Criar trigger BEFORE INSERT
CREATE TRIGGER set_order_defaults
BEFORE INSERT ON orders_new
FOR EACH ROW
BEGIN
-- Definir automaticamente a data do pedido para a data atual
SET NEW.order_date = COALESCE(NEW.order_date, date('now', 'localtime'));
-- Definir automaticamente o horário de criação
SET NEW.created_at = COALESCE(NEW.created_at, datetime('now', 'localtime'));
-- Se a quantidade for nula ou 0, padronizar para 1
SET NEW.quantity = CASE WHEN NEW.quantity IS NULL OR NEW.quantity <= 0 THEN 1 ELSE NEW.quantity END;
END;
-- Testar: inserir sem especificar order_date e status
INSERT INTO orders_new (customer_name, product_id, quantity) VALUES ('John Doe', 1, 3);
-- Verificar o resultado preenchido automaticamente
SELECT * FROM orders_new;
Saída Esperada:
id customer_name product_id quantity order_date status created_at
1 John Doe 1 3 2026-06-28 pending 2026-06-28 10:30:00
SET NEW.coluna = valor, enquanto PostgreSQL requer usar NEW.coluna := valor em triggers BEFORE para modificar novos valores.
Cenários de Aplicação
Cenário 1: Atualização Automática de uma Tabela de Resumo de Pedidos (Dificuldade ⭐⭐⭐)
-- Versão SQLite
-- Criar tabela de resumo de pedidos
CREATE TABLE IF NOT EXISTS order_summary (
customer_id INTEGER PRIMARY KEY,
total_orders INTEGER DEFAULT 0,
total_amount REAL DEFAULT 0,
last_order_date TEXT
);
-- Criar trigger: atualizar resumo automaticamente na inserção de pedido
CREATE TRIGGER update_order_summary_insert
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
INSERT OR REPLACE INTO order_summary (customer_id, total_orders, total_amount, last_order_date)
SELECT
NEW.customer_id,
COALESCE(os.total_orders, 0) + 1,
COALESCE(os.total_amount, 0) + NEW.amount,
NEW.order_date
FROM (SELECT 1) AS dummy
LEFT JOIN order_summary os ON os.customer_id = NEW.customer_id;
END;
-- Criar trigger: atualizar resumo automaticamente na exclusão de pedido
CREATE TRIGGER update_order_summary_delete
AFTER DELETE ON orders
FOR EACH ROW
BEGIN
UPDATE order_summary
SET
total_orders = total_orders - 1,
total_amount = total_amount - OLD.amount
WHERE customer_id = OLD.customer_id;
-- Se a contagem de pedidos chegar a 0, excluir o registro de resumo
DELETE FROM order_summary
WHERE customer_id = OLD.customer_id AND total_orders <= 0;
END;
Cenário 2: Validação de Dados e Preenchimento Automático (Dificuldade ⭐⭐⭐)
-- Versão SQLite: cálculo automático do total do pedido
CREATE TRIGGER calculate_order_total
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
-- Definir automaticamente o horário de criação
SELECT NEW.created_at IS NULL THEN
SET NEW.created_at = datetime('now', 'localtime');
END IF;
-- Validar que o valor deve ser positivo
IF NEW.amount < 0 THEN
SELECT RAISE(ABORT, 'O valor do pedido não pode ser negativo');
END IF;
END;
❓ Perguntas Frequentes
P: Triggers afetam a performance do banco de dados? R: Sim. Cada ativação de trigger executa operações SQL adicionais. Triggers muitas vezes ou lógica complexa podem degradar a performance de escrita. Mantenha a lógica das triggers simples e evite operações demoradas dentro delas.
P: Uma tabela pode ter múltiplas triggers? R: SQLite permite apenas uma trigger por evento e momento. MySQL e PostgreSQL permitem múltiplas triggers e permitem especificar a ordem de execução com FOLLOWS/PRECEDES.
P: Triggers podem acessar outras tabelas? R: Sim. Triggers podem consultar e modificar dados em outras tabelas, mas tenha cuidado para evitar triggers circulares e deadlocks.
P: Como faço para depurar uma trigger? R: Você pode inserir dados de teste temporários em uma tabela de log dentro da trigger para observar o fluxo de execução. MySQL pode usar a instrução SIGNAL para lançar mensagens de erro personalizadas.
📖 Resumo
Nesta lição aprendemos:
- O conceito e mecanismo de triggers
- A diferença entre os momentos de trigger BEFORE e AFTER
- Como usar as referências NEW e OLD
- Sintaxe e exemplos de triggers SQLite
- Casos de uso típicos de triggers (auditoria, atualizações em cascata, validação de dados)
- O conceito de agendador de eventos (conhecimento estendido MySQL)
📝 Exercícios
-
Exercício Básico: Crie uma trigger que faça backup automaticamente das informações de um funcionário para uma tabela
employees_backupquando o funcionário for excluído. -
Exercício Intermediário: Crie um sistema de triggers que implemente o seguinte:
- Quando um novo pedido é inserido, reduzir automaticamente o estoque do produto
- Quando o estoque for insuficiente, prevenir a inserção do pedido e mostrar um erro
-
Questão Reflexiva: Tanto triggers quanto código de aplicação podem implementar lógica de negócios. Para quais cenários cada um é mais adequado? Como você escolhe?
Próxima Lição → 24-practice-advanced.md



