DevGuideTK
← Trilha Backend

Níveis de isolamento

O que duas transações simultâneas enxergam uma da outra e as anomalias que cada nível permite.

As decisões de isolamento são três: qual nível usar por padrão, como proteger cada operação sensível e como lidar com as transações que o banco recusa.

Qual nível por padrão

NívelProtege contraCustoBom para
Read committedLeitura sujaQuase nenhumO padrão da maioria das aplicações, com proteções pontuais
Repeatable readO acima, leitura não repetível e fantasma (PostgreSQL também barra a atualização perdida)Erros de serialização no PostgreSQL; travas de intervalo no MySQLRelatórios e exportações que precisam de uma fotografia consistente
SerializableTodas as anomaliasTransações recusadas, que precisam ser repetidas; no MySQL, mais travas e impassesRegras sobre várias linhas, ou quando ninguém consegue provar que o nível mais fraco basta

A abordagem mais comum: manter o padrão do banco e proteger cada operação sensível com a técnica certa. A alternativa, usar serializable em tudo, é mais simples de raciocinar e cobra em recusas e repetições. Ela compensa em sistemas com muitas regras de negócio entrelaçadas e pouca disputa pelas mesmas linhas.

Saiba qual é o padrão do seu banco: read committed no PostgreSQL, no SQL Server e no Oracle; repeatable read no MySQL. E não conte com o comportamento do nível pelo nome: no teste do nível Conceito, o repeatable read do MySQL deixou passar a atualização perdida, e o do PostgreSQL a recusou.

Como proteger cada anomalia

AnomaliaTécnicaFunciona em qualquer nível?
Atualização perdidaGravação condicional: UPDATE ... SET saldo = saldo - 10 WHERE id = 1 AND saldo >= 10Sim
Trava pessimista: SELECT ... FOR UPDATE antes de calcularSim
Trava otimista: coluna versao e WHERE versao = $lidaSim
Escrita enviesadaSerializable com repetição—
Travar uma linha comum a todas: SELECT ... FROM escalas WHERE id = $1 FOR UPDATE antes de contarSim
Restrição no banco, quando a regra cabe numa (UNIQUE, EXCLUDE, CHECK)Sim
Leitura não repetível e fantasmaRepeatable read para o relatório inteiro—
Uma consulta só, em vez de váriasSim

A atualização perdida tem três soluções simples, e nenhuma depende do nível. O tópico de transações compara as três.

A escrita enviesada é a que pede atenção, porque as transações alteram linhas diferentes e as travas de linha não se cruzam. As saídas:

SaídaComo funcionaQuando
SerializableO banco detecta o conflito e recusa uma das transaçõesA regra é complexa, ou há muitas regras assim
Trava num registro comumTodas as transações da regra travam a mesma linha antes de contar, e passam a rodar em filaA regra tem um "dono" natural: a escala, a sala, a conta
Restrição no bancoO banco recusa o estado inválido, qualquer que seja a ordemA regra cabe numa restrição: "uma reserva por sala no mesmo horário" com EXCLUDE
Materializar o conflitoCriar uma linha que todas as transações precisam alterar, como um contadorNão há registro comum, e o serializable não é uma opção

Como repetir as transações recusadas

BancoCódigos que pedem repetição
PostgreSQL40001 (falha de serialização) e 40P01 (impasse)
MySQL1213 (impasse) e 1205 (tempo de espera por trava esgotado)
SQL Server1205 (vítima de impasse)

A repetição tem regras:

  1. A transação inteira, desde o começo, inclusive as leituras. Repetir só o comando que falhou usa dados velhos.
  2. Só os erros de conflito. Uma violação de UNIQUE ou de CHECK não melhora na segunda tentativa.
  3. Com limite e espera crescente com variação aleatória, para as transações em disputa não colidirem de novo no mesmo instante.
  4. Nada fora do banco dentro da transação. Um e-mail enviado ou uma chamada a outra API não se desfazem quando o banco recusa a transação. Faça isso depois do COMMIT, ou com uma fila de saída, como mostra o tópico de webhooks.

No teste da Implementação, dez transações simultâneas em serializable geraram entre 10 e 20 repetições, e o resultado ficou correto nas cinco linguagens.

Quanto custa

FatorEfeito
Disputa pelas mesmas linhasQuanto mais transações mexem nos mesmos dados ao mesmo tempo, mais recusas no serializable
Duração da transaçãoTransações longas acumulam dependências e são recusadas com mais frequência; mantenha-as curtas
Transações só de leituraNo PostgreSQL, SERIALIZABLE READ ONLY DEFERRABLE espera uma fotografia segura e nunca é recusada; útil para relatórios

Resumo da decisão

  1. Conheça o padrão do seu banco e não conte com o nome do nível: teste.
  2. Atualização perdida: gravação condicional, FOR UPDATE ou versão, em qualquer nível.
  3. Escrita enviesada: serializable, trava num registro comum ou restrição no banco.
  4. Relatórios consistentes: repeatable read, ou uma consulta só.
  5. Repetição da transação inteira, só para os códigos de conflito, com limite e espera aleatória.
  6. Transações curtas, sem efeitos fora do banco.

O próximo nível mostra a regra do plantão em serializable, com a repetição, nas cinco linguagens.

Prompts para aprofundar

Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.

  • Escolher o nível e as proteções do meu sistema

    Quero definir o nível de isolamento e as proteções de concorrência do meu sistema.
    
    Pergunte qual banco eu uso, quais operações leem, calculam e gravam, quais regras envolvem várias linhas e qual é o volume de escrita simultânea.
    
    Para cada operação sensível, recomende uma proteção (gravação condicional, trava pessimista, trava otimista, serializable, trava num registro comum ou restrição) e explique o porquê. No final, diga se faz sentido mudar o nível padrão.
  • Repetir transações recusadas

    Quero implementar a repetição de transações recusadas pelo banco.
    
    Pergunte qual banco, linguagem e framework eu uso.
    
    Explique:
    1. Quais códigos de erro pedem repetição no meu banco, e quais não.
    2. Por que repetir a transação inteira, e não o comando.
    3. Limite de tentativas e espera crescente com variação aleatória.
    4. O que fazer com e-mails, filas e chamadas externas que estavam dentro da transação.
    5. Como medir quantas repetições acontecem em produção.
  • Relatórios consistentes sem travar o sistema

    Preciso gerar relatórios e exportações com dados consistentes, enquanto o sistema continua recebendo escritas.
    
    Pergunte qual banco eu uso, o tamanho dos relatórios e se há réplicas de leitura.
    
    Compare para o meu caso: repeatable read, serializable read only deferrable (no PostgreSQL), uma consulta só, uma réplica de leitura e uma cópia dos dados para análise. Explique o efeito de cada opção nas escritas do sistema.