Processamento de Transações

Processamento de Transações

🌍 Analogia do Mundo Real

Imagine uma transferência bancária — você transfere 1000 da Conta A para a Conta B:

  1. Deduzir 1000 da Conta A
  2. Adicionar 1000 à Conta B

Se a etapa 1 tiver sucesso mas a etapa 2 falhar (ex: crash do sistema), A tem menos dinheiro mas B não recebeu — isso é um grande problema.

Uma transação vincula essas duas etapas em uma "operação atômica": ou ambas as etapas têm sucesso (COMMIT) ou ambas são revertidas (ROLLBACK). Nunca existe um estado "pela metade".


🎯 Conceitos Fundamentais

O que é uma Transação

Uma transação é uma sequência indivisível de operações SQL que ou todas executam com sucesso ou todas revertem. É o mecanismo central para garantir a consistência dos dados no banco de dados.

Propriedades ACID

Propriedade Inglês Significado
Atomicidade Atomicity Todas as operações em uma transação ou têm sucesso ou são revertidas
Consistência Consistency O banco de dados transição de um estado consistente para outro
Isolamento Isolation Transações concorrentes não interferem umas nas outras, como se fossem executadas em série
Durabilidade Durability Uma vez confirmados, os dados são salvos permanentemente, mesmo se o sistema falhar
💡 Dica de memorização: A-C-I-D — Atomicidade vem primeiro, Durabilidade vem por último, como uma cadeia completa de proteção.

BEGIN / COMMIT / ROLLBACK

SQL
-- Iniciar uma transação
BEGIN;  -- ou START TRANSACTION

-- Executar uma série de operações
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;

-- Tudo certo, confirmar
COMMIT;

-- Algo deu errado, reverter
ROLLBACK;

SAVEPOINT — Pontos de Salvamento

Defina um "ponto de verificação" dentro de uma transação. Você pode reverter para um ponto de salvamento específico sem afetar as operações anteriores a ele.

SQL
BEGIN;

INSERT INTO orders VALUES (1020, 101, 1, '2026-06-28', 500.00, 'pending');
SAVEPOINT sp1;

INSERT INTO order_items VALUES (1020, 1, 2, 100.00);
SAVEPOINT sp2;

-- Se a segunda etapa tiver um erro, revertemos apenas para sp1
ROLLBACK TO sp1;

-- Manter as operações da primeira etapa
COMMIT;
Comando Finalidade
SAVEPOINT nome Definir um ponto de salvamento
ROLLBACK TO nome Reverter para o ponto de salvamento especificado (mantém operações anteriores ao ponto)
RELEASE SAVEPOINT nome Excluir um ponto de salvamento

Níveis de Isolamento de Transações

Quando múltiplas transações operam nos mesmos dados simultaneamente, os seguintes problemas podem ocorrer:

Problema Descrição Exemplo
Leitura Suja Ler dados que outra transação não confirmou Transação A modifica dados mas não confirmou; Transação B lê o valor modificado
Leitura Não Repetível Ler a mesma linha duas vezes na mesma transação produz resultados diferentes Transação A lê a mesma linha duas vez; entre as leituras, Transação B modifica e confirma essa linha
Leitura Fantasma Executar a mesma consulta duas vezes na mesma transação produz contagens de linhas diferentes Transação A consulta duas vezes; entre as consultas, Transação B insere novas linhas

SQL define quatro níveis de isolamento:

Nível de Isolamento Leitura Suja Leitura Não Repetível Leitura Fantasma Descrição
READ UNCOMMITTED ✅ Possível ✅ Possível ✅ Possível Nível mais baixo, raramente usado
READ COMMITTED ❌ Não ✅ Possível ✅ Possível Padrão do Oracle/PostgreSQL
REPEATABLE READ ❌ Não ❌ Não ✅ Possível Padrão do MySQL
SERIALIZABLE ❌ Não ❌ Não ❌ Não Nível mais alto, pior performance
SQL
-- Ver nível de isolamento atual
SELECT @@transaction_isolation;

-- Definir nível de isolamento
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

Deadlocks

Um deadlock ocorre quando duas transações estão esperando que a outra libere recursos:

TEXT
Transação A: Bloqueia Tabela 1 → Espera pela Tabela 2
Transação B: Bloqueia Tabela 2 → Espera pela Tabela 1
→ Esperando para sempre, nunca pode completar

Como o banco de dados lida com isso: Detecta automaticamente o deadlock, seleciona uma transação como "vítima" e a reverte, permitindo que a outra continue.

Estratégias para evitar deadlocks:

Melhores Práticas

Princípio Descrição
Manter transações curtas Reduzir tempo de retenção de bloqueios, melhorar concorrência
Não esperar entrada do usuário em uma transação Transações devem completar rapidamente
Usar níveis de isolamento apropriados Não usar o nível mais alto por padrão
Usar ordem de acesso consistente Reduzir probabilidade de deadlock
Adicionar tratamento de erros Reverter prontamente quando erros ocorrerem

📝 Sintaxe Básica

SQL
-- Iniciar uma transação
BEGIN;  -- MySQL, PostgreSQL
START TRANSACTION;  -- Também suportado pelo MySQL

-- Confirmar a transação (todas as operações têm efeito permanente)
COMMIT;

-- Reverter a transação (desfaz todas as operações)
ROLLBACK;

-- Pontos de salvamento
SAVEPOINT nome_do_ponto;
ROLLBACK TO nome_do_ponto;
RELEASE SAVEPOINT nome_do_ponto;

-- Definir nível de isolamento
SET TRANSACTION ISOLATION LEVEL nível_de_isolamento;
-- Níveis de isolamento: READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE

-- Definir nível de isolamento global (afeta todas as novas conexões)
SET GLOBAL TRANSACTION ISOLATION LEVEL nível_de_isolamento;

-- Interruptor de autocommit (MySQL tem como padrão ON)
SET autocommit = 0;  -- Desabilitar autocommit, requer COMMIT manual
SET autocommit = 1;  -- Habilitar autocommit (padrão)
💡 Dica:

  • MySQL tem como padrão autocommit = 1, onde cada instrução SQL é confirmada automaticamente. Antes de usar transações, execute BEGIN ou SET autocommit = 0
  • Instruções DDL (CREATE, ALTER, DROP) confirmam implicitamente a transação atual
  • Quando uma conexão é desconectada, transações não confirmadas são automaticamente revertidas

📌 Exemplos

Exemplo: Transação de Criação de Pedido (Pedido + Dedução de Estoque) (Dificuldade ⭐⭐)

SQL
-- Cenário: Um cliente faz um pedido de um produto; é necessário criar o pedido e deduzir o estoque simultaneamente
BEGIN;

-- Etapa 1: Criar o pedido
INSERT INTO orders (order_id, customer_id, employee_id, order_date, total_amount, status)
VALUES (1020, 101, 1, '2026-06-28', 6999.00, 'pending');

-- Etapa 2: Deduzir estoque
UPDATE products SET stock = stock - 1 WHERE product_id = 1;

-- Etapa 3: Verificar se o estoque é suficiente (reverter se estoque < 0)
-- Na prática, isso geralmente é tratado pela lógica da aplicação ou triggers

-- Tudo certo, confirmar
COMMIT;
▶ Experimente

Se ocorrer um erro no meio:

SQL
BEGIN;

INSERT INTO orders (order_id, customer_id, employee_id, order_date, total_amount, status)
VALUES (1021, 102, 3, '2026-06-28', 129.00, 'pending');

UPDATE products SET stock = stock - 1 WHERE product_id = 2;

-- Suponha que descobrimos estoque insuficiente, reverter toda a transação
ROLLBACK;
-- Tanto o pedido quanto o estoque são restaurados ao estado anterior à transação

Exemplo: Usando SAVEPOINT para Reversão Parcial (Dificuldade ⭐⭐⭐)

SQL
BEGIN;

-- Primeiro pedido: bem-sucedido
INSERT INTO orders VALUES (1022, 103, 4, '2026-06-28', 3500.00, 'pending');
UPDATE products SET stock = stock - 1 WHERE product_id = 4;
SAVEPOINT after_first_order;

-- Segundo pedido: erro
INSERT INTO orders VALUES (1023, 104, 4, '2026-06-28', 2200.00, 'pending');
UPDATE products SET stock = stock - 1 WHERE product_id = 5;
SAVEPOINT after_second_order;

-- Descobrimos um problema com o segundo pedido, reverter para após o primeiro
ROLLBACK TO after_first_order;

-- O primeiro pedido ainda é válido, confirmar
COMMIT;
-- Resultado: Pedido 1022 é mantido, Pedido 1023 é revertido
▶ Experimente

Verificação:

SQL
SELECT order_id, total_amount, status FROM orders WHERE order_id >= 1022;
TEXT
order_id | total_amount | status
---------+-------------+--------
    1022 |     3500.00 | pending

Explicação: ROLLBACK TO after_first_order apenas desfaz operações após o ponto de salvamento. O primeiro pedido e a dedução de estoque são preservados.


🎬 Prática de Cenários

Cenário 1: Ajuste Salarial em Lote de Funcionários (com Tratamento de Erros) (Dificuldade ⭐⭐⭐)

SQL
BEGIN;

-- Dar aumento de 10% para o departamento de Vendas
UPDATE employees 
SET salary = salary * 1.10 
WHERE department_id = (SELECT department_id FROM departments WHERE department_name = 'Sales');

SAVEPOINT after_sales_raise;

-- Dar aumento de 8% para o departamento de Tecnologia
UPDATE employees 
SET salary = salary * 1.08 
WHERE department_id = (SELECT department_id FROM departments WHERE department_name = 'Tech');

SAVEPOINT after_tech_raise;

-- Suponha que a aprovação do orçamento não passou, desfazer apenas o aumento do departamento de Tecnologia
ROLLBACK TO after_sales_raise;

-- O aumento do departamento de Vendas é mantido, confirmar
COMMIT;

Ponto-chave: SAVEPOINT permite "reversão parcial", adequado para operações em lote que requerem controle flexível.

Cenário 2: Simulando uma Transferência e Tratando Deadlocks (Dificuldade ⭐⭐⭐)

SQL
-- Sessão A: Transferir orçamento do departamento 1 para o departamento 2
BEGIN;
UPDATE departments SET budget = budget - 50000 WHERE department_id = 1;
-- Aguardar um momento...
UPDATE departments SET budget = budget + 50000 WHERE department_id = 2;
COMMIT;

-- Sessão B: Simultaneamente transferir orçamento do departamento 2 para o departamento 1 (outra conexão)
BEGIN;
UPDATE departments SET budget = budget - 30000 WHERE department_id = 2;
UPDATE departments SET budget = budget + 30000 WHERE department_id = 1;
COMMIT;

Prevenção de deadlock:

SQL
-- Ambas as sessões acessam departamentos em ordem ascendente por department_id
-- Sessão A:
BEGIN;
UPDATE departments SET budget = budget - 50000 WHERE department_id = 1;  -- Bloqueia 1 primeiro
UPDATE departments SET budget = budget + 50000 WHERE department_id = 2;  -- Depois bloqueia 2
COMMIT;

-- Sessão B:
BEGIN;
UPDATE departments SET budget = budget + 30000 WHERE department_id = 1;  -- Também bloqueia 1 primeiro
UPDATE departments SET budget = budget - 30000 WHERE department_id = 2;  -- Depois bloqueia 2
COMMIT;

Ponto-chave: Usar uma ordem de acesso consistente é a maneira mais simples e eficaz de evitar deadlocks.


❓ Perguntas Frequentes

P: MySQL tem autocommit como padrão — como uso transações? R: MySQL tem como padrão autocommit = 1, onde cada instrução SQL é confirmada automaticamente. Para usar transações, execute BEGIN (ou START TRANSACTION) primeiro; as instruções SQL seguintes não serão confirmadas automaticamente até que você execute COMMIT ou ROLLBACK.

P: Posso fazer ROLLBACK após COMMIT? R: Não. COMMIT é o fim de uma transação; uma vez confirmados, os dados são salvos permanentemente e não podem ser desfeitos. Para "desfazer" dados confirmados, você deve executar uma operação reversa em uma nova transação (ex: UPDATE de volta ao valor original).

P: Qual nível de isolamento devo escolher? R: Para a maioria dos cenários, use o padrão do banco de dados (MySQL tem como padrão REPEATABLE READ, Oracle/PostgreSQL tem como padrão READ COMMITTED). Use SERIALIZABLE apenas quando precisar explicitamente prevenir leituras fantasmas e puder aceitar o compromisso de performance.

P: Instruções DDL (CREATE TABLE, ALTER TABLE) são controladas por transações? R: Não. Instruções DDL confirmam implicitamente a transação atual. Após executar DDL em uma transação, as instruções SQL anteriores não podem mais ser revertidas. Este é o comportamento do MySQL; no PostgreSQL, DDL pode ser revertida.


📖 Resumo

Conceito Descrição
Transação Um grupo de operações de banco de dados indivisíveis
ACID Atomicidade, Consistência, Isolamento, Durabilidade
BEGIN Iniciar uma transação
COMMIT Confirmar uma transação, torná-la permanente
ROLLBACK Reverter uma transação, desfazer tudo
SAVEPOINT Um ponto de verificação dentro de uma transação, suporta reversão parcial
Nível de Isolamento Controla a visibilidade entre transações concorrentes
Deadlock Duas transações esperando uma pela outra; o banco de dados detecta automaticamente e reverte uma

📝 Exercícios

  1. Escreva uma transação que insere um novo pedido na tabela orders enquanto deduz o estoque do produto correspondente na tabela products. Se o estoque for insuficiente, reverter toda a transação.
  2. Use SAVEPOINT para implementar uma transação que insere 3 registros de pedidos, depois reverte o 3º enquanto mantém os 2 primeiros.
  3. Verifique o nível de isolamento padrão do seu banco de dados e tente definir para READ COMMITTED para observar o impacto em leituras e escritas concorrentes.
  4. Questão reflexiva: Se uma transação levar muito tempo para executar, qual será o impacto em outras transações? Como isso pode ser otimizado?

Próxima Lição

👉 22-stored-procedures - Procedimentos Armazenados: Aprenda sobre criação e chamada de procedimentos armazenados, parâmetros de entrada/saída, instruções de controle de fluxo e as aplicações práticas de procedimentos armazenados.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%