Bora revisar os tipos de transações! No mundo das transações em banco de dados, existem três grandes "vilões" que podem acabar com o seu dia: Dirty Read, Non-Repeatable Read e Phantom Read. Essas "anomalias" aparecem quando o nível de isolamento das transações não é suficiente. Hoje vamos entender quem são esses vilões, como eles aparecem e — o mais importante — como lidar com eles.
Antes de ir pros exemplos, bora lembrar o que cada um significa.
Dirty Read (Leitura Suja):
Você lê dados que foram alterados, mas a transação que fez a alteração ainda não foi confirmada (COMMIT) ou, pior ainda, pode ser desfeita (ROLLBACK). É tipo quando você transfere dinheiro pra um amigo, olha seu saldo e vê que ficou zerado, mas depois desiste e pega o dinheiro de volta. Mágica!Non-Repeatable Read (Leitura Não Repetível):
Você lê os mesmos dados duas vezes dentro de uma transação, mas entre as leituras outra transação mudou esses dados, e você vê dois resultados diferentes. É como olhar a data de nascimento no RG, emprestar pra um amigo que muda os números, e quando você olha de novo, sua data mudou.Phantom Read (Leitura Fantasma):
Você faz a mesma consulta duas vezes, mas na segunda aparecem linhas a mais, inseridas por outra transação. É tipo contar as pessoas numa sala, e alguém traz mais amigos sem você perceber.
Problema Dirty Read
Imagina que temos uma tabela accounts:
CREATE TABLE accounts (
account_id SERIAL PRIMARY KEY,
owner TEXT NOT NULL,
balance NUMERIC(10, 2) NOT NULL
);
INSERT INTO accounts (owner, balance) VALUES ('Alice', 1000), ('Bob', 500);
A Transação 1 altera o saldo, mas ainda não terminou, e a Transação 2 tenta ler esses dados ao mesmo tempo.
Transação 1:
BEGIN;
UPDATE accounts SET balance = balance - 200 WHERE owner = 'Alice';
-- O saldo da Alice virou 800, mas a transação ainda não terminou.
Transação 2:
BEGIN;
SELECT balance FROM accounts WHERE owner = 'Alice'; -- Vemos saldo: 800 (leitura suja).
ROLLBACK; -- Transação 1 é desfeita.
Agora a Transação 2 está usando dados errados, porque a Transação 1 desfez as alterações. Dá pra evitar isso usando o nível de isolamento READ COMMITTED, que não deixa ver alterações de transações não confirmadas.
Problema Non-Repeatable Read
Pensa que a Transação 1 lê os dados, outra transação altera eles, e a Transação 1 lê de novo. Os dados mudaram.
Transação 1:
BEGIN;
SELECT balance FROM accounts WHERE owner = 'Bob'; -- Vemos saldo: 500.
Transação 2 em paralelo:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE owner = 'Bob';
COMMIT;
Transação 1 de novo:
SELECT balance FROM accounts WHERE owner = 'Bob'; -- Vemos saldo: 400.
COMMIT;
Repara como os dados mudaram dentro da mesma transação. Em cenários reais isso pode ser crítico, tipo em relatórios financeiros. Pra resolver, usa um nível de isolamento mais alto, tipo REPEATABLE READ.
Problema Phantom Read
Imagina que temos uma tabela orders:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer TEXT NOT NULL,
total NUMERIC(10, 2) NOT NULL
);
INSERT INTO orders (customer, total) VALUES ('Alice', 100), ('Bob', 200);
A Transação 1 conta quantos pedidos existem, outra transação adiciona um novo pedido, e a Transação 1 conta de novo.
Transação 1:
BEGIN;
SELECT COUNT(*) FROM orders; -- Vemos: 2.
Transação 2 em paralelo:
BEGIN;
INSERT INTO orders (customer, total) VALUES ('Charlie', 300);
COMMIT;
Transação 1 de novo:
SELECT COUNT(*) FROM orders; -- Vemos: 3. Apareceu um novo pedido "fantasma"!
COMMIT;
Pra evitar leituras fantasmas, precisa do nível de isolamento SERIALIZABLE, que bloqueia totalmente alterações paralelas que afetam o resultado.
Como evitar anomalias
Níveis de isolamento vs. Anomalias
| Nível de isolamento | Dirty Read |
Non-Repeatable Read |
Phantom Read |
|---|---|---|---|
Read Uncommitted |
❌ Sim | ❌ Sim | ❌ Sim |
Read Committed |
✅ Não | ❌ Sim | ❌ Sim |
Repeatable Read |
✅ Não | ✅ Não | ❌ Sim |
Serializable |
✅ Não | ✅ Não | ✅ Não |
Como escolher o nível de isolamento certo?
- Se você precisa de acesso rápido aos dados e as anomalias não são críticas (tipo análise em dados antigos) — usa
READ COMMITTED. - Se precisa de estabilidade dos dados dentro de uma transação — usa
REPEATABLE READ. - Se quer máxima isolação e consistência — escolhe
SERIALIZABLE. Mas lembra: a performance pode cair.
Dicas práticas
Use transações com níveis de isolamento que fazem sentido pro seu caso. Por exemplo:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT ...;
COMMIT;
Adicione índices pra minimizar bloqueios nas tabelas e acelerar as consultas.
Use queries otimizadas pra evitar bloqueios longos, principalmente no nível SERIALIZABLE.
Erros comuns e como evitar
Às vezes, escolher o nível de isolamento errado causa conflitos e queda de performance. Por exemplo, usar SERIALIZABLE num sistema com muitas transações paralelas pode causar bloqueios e "fome" de transações.
Pra evitar isso, analise suas queries, teste a performance em diferentes níveis de isolamento e use índices adequados.
GO TO FULL VERSION