🧠FFVAcademy
🔒

Transações e isolation levels: ACID sem decoreba

15 min de leitura·+75 XP

ACID é a garantia que diferencia um banco de dados de um arquivo de texto. Atomicidade, Consistência, Isolamento, Durabilidade — não são decoreba, são propriedades com implementação concreta que você precisa entender para não introduzir bugs de concorrência sutis.

ACID: o que cada propriedade garante

-- Atomicidade: tudo ou nada
BEGIN;
UPDATE contas SET saldo = saldo - 100 WHERE id = 1;  -- debita Alice
UPDATE contas SET saldo = saldo + 100 WHERE id = 2;  -- credita Bob
-- Se o segundo UPDATE falhar, o primeiro é REVERTIDO automaticamente
COMMIT;   -- ambos ou nenhum

-- Consistência: constraints são verificadas no COMMIT
BEGIN;
UPDATE contas SET saldo = saldo - 1000 WHERE id = 1;
-- CHECK (saldo >= 0) é violado → ROLLBACK automático ao tentar COMMIT
COMMIT;

-- Isolamento: transações concorrentes não se veem (depende do nível)
-- Ver seção de Isolation Levels abaixo

-- Durabilidade: após COMMIT, dado está no disco (WAL garante)
-- PostgreSQL usa Write-Ahead Log: toda mudança vai para WAL antes do heap
-- Em caso de crash, recovery reproduz o WAL
-- synchronous_commit = on (default): COMMIT espera WAL estar em disco

Isolation Levels: o trade-off consistência × performance

NívelDirty ReadNon-Repeatable ReadPhantom ReadAnomalias seriais
Read UncommittedPossível*PossívelPossívelPossível
Read Committed (padrão PG)ImpossívelPossívelPossívelPossível
Repeatable ReadImpossívelImpossívelImpossível*Possível
SerializableImpossívelImpossívelImpossívelImpossível
-- Alterar isolation level para uma transação:
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- ... operações ...
COMMIT;

-- Ou para a sessão inteira:
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- Exemplo de Non-Repeatable Read (Read Committed):
-- T1: BEGIN; SELECT saldo FROM contas WHERE id=1;  → retorna 1000
-- T2: BEGIN; UPDATE contas SET saldo=500 WHERE id=1; COMMIT;
-- T1: SELECT saldo FROM contas WHERE id=1;  → retorna 500 (mudou!)
-- Com Repeatable Read, T1 veria 1000 na segunda leitura

-- Serialization Anomaly (detectada pelo Serializable PG):
-- T1: SELECT SUM(quantidade) FROM estoque; → 100
-- T2: SELECT SUM(quantidade) FROM estoque; → 100
-- T1: INSERT INTO movimentos (tipo, qtd) VALUES ('entrada', 50) WHERE 100 < 200;
-- T2: INSERT INTO movimentos (tipo, qtd) VALUES ('saida', 100) WHERE 100 >= 50;
-- Ambas commitam — mas qualquer execução serial teria comportamento diferente!
-- Serializable aborta uma delas com: ERROR: could not serialize access

Locking: FOR UPDATE, FOR SHARE, SKIP LOCKED

-- SELECT FOR UPDATE: lock exclusivo nas linhas (para update ou delete)
BEGIN;
SELECT id, saldo FROM contas WHERE id = 1 FOR UPDATE;
-- Agora: nenhuma outra transação pode UPDATE/DELETE/FOR UPDATE nessa linha
-- até este COMMIT/ROLLBACK
UPDATE contas SET saldo = saldo - 100 WHERE id = 1;
COMMIT;

-- SELECT FOR SHARE: lock compartilhado (múltiplos leitores, bloqueia writers)
-- Útil quando você lê dado que outros não devem modificar mas podem ler

-- SKIP LOCKED: ignora linhas lockadas (fila de trabalho)
-- Padrão de job queue sem conflito entre workers:
BEGIN;
SELECT id, payload
FROM jobs
WHERE status = 'pendente'
ORDER BY prioridade DESC, id
LIMIT 1
FOR UPDATE SKIP LOCKED;  -- pega o próximo não-lockado
-- ... processar job ...
UPDATE jobs SET status = 'concluido' WHERE id = $1;
COMMIT;

-- NOWAIT: falha imediatamente se não conseguir o lock
SELECT * FROM tabela WHERE id = 1 FOR UPDATE NOWAIT;
-- ERROR: could not obtain lock on row in relation "tabela"
-- Útil para detectar contention sem esperar timeout

-- Advisory locks: locks customizados no nível de aplicação
SELECT pg_advisory_lock(42);        -- lock exclusivo de id 42
-- ... operação crítica ...
SELECT pg_advisory_unlock(42);
Guia prático: use Read Committed (padrão) para operações CRUD simples. Use Repeatable Read para relatórios que precisam de snapshot consistente. Use Serializable quando a lógica tem read-modify-write complexo. Use SELECT FOR UPDATE SKIP LOCKED para filas de trabalho. Nunca faça read-modify-write sem transação em sistemas concorrentes.
💡
Próximo: Normalização e modelagem — 1NF, 2NF, 3NF e quando desnormalizar intencionalmente.
🧩

Quiz rápido

3 perguntas · Acerte tudo e ganhe o badge 🎯 Gabarito

Continue lendo