17 de Maio de 2025
Bancos de Dados e Concorrência
Como pensar quando duas transações disputam o mesmo dado e por que corretude no banco não nasce só de fazer um select e depois um update.
Andrews Ribeiro
Founder & Engineer
5 min Intermediario Sistemas
O problema
Muita conversa sobre concorrência começa na aplicação e termina cedo demais.
Mas vários bugs realmente perigosos aparecem no ponto em que duas execuções tentam decidir e gravar sobre o mesmo dado.
Exemplos clássicos:
- vender a última unidade duas vezes
- cobrar duas vezes a mesma intenção
- deixar saldo negativo
- sobrescrever um estado mais novo com uma decisão baseada em leitura velha
Quando isso acontece, o banco deixa de ser só armazenamento.
Ele vira parte central da corretude.
Modelo mental
Pense assim:
banco e concorrência é o problema de manter uma regra de negócio verdadeira mesmo quando duas transações tentam mudá-la ao mesmo tempo.
Isso ajuda porque tira a conversa de abstração solta.
O ponto não é “usar transação porque sim”.
O ponto é responder:
- qual dado está sendo disputado?
- qual invariável não pode quebrar?
- qual proteção garante isso com custo aceitável?
Quebrando o problema
O erro comum é read, decide, write inocente
Esse fluxo aparece toda hora:
- ler valor atual
- decidir com base nele
- gravar novo valor
Sozinho, parece certo.
Sob concorrência, duas transações podem ler o mesmo estado antigo e tomar a mesma decisão como se fossem as únicas no mundo.
É aí que nasce muito bug sério.
Operação atômica resolve mais do que muita gente imagina
Às vezes você não precisa de uma grande coreografia transacional.
Precisa só transformar a intenção em uma escrita atômica.
Exemplos:
- decrementar estoque apenas se ainda houver estoque
- atualizar saldo só se a condição continuar válida
- mudar status só se ele ainda estiver no estado esperado
Quando a regra cabe numa operação única e verificável, isso costuma ser mais simples e mais barato do que lockar meio sistema.
Transação ajuda quando a regra atravessa mais de um passo
Se a corretude depende de várias leituras e escritas coerentes entre si, a conversa sobe de nível.
Aí entram coisas como:
- começar transação
- garantir que a visão dos dados continue aceitável
- persistir ou abortar em bloco
Só que “usar transação” ainda não fecha a discussão.
Porque o comportamento real depende também de isolamento, contenção e padrão de acesso.
Lock é defesa útil, mas cobra preço
Lock pode ser exatamente o que protege um recurso muito disputado.
Mas ele cobra:
- menos paralelismo
- mais espera
- risco de contenção alta
- possibilidade de deadlock se o desenho for ruim
Por isso lock não é prêmio de maturidade.
É ferramenta cara que vale quando a disputa justifica.
Isolamento não é detalhe acadêmico
Muita gente escuta “nível de isolamento” e desliga.
Mas a pergunta prática é simples:
que tipo de leitura ou interferência concorrente eu aceito entre duas transações?
Dependendo do caso, você pode tolerar alguma variação.
Em outros, não.
Fluxo financeiro, reserva e estoque costumam exigir mais cuidado do que consulta agregada para dashboard.
Banco não salva modelagem ruim sozinho
Outro erro comum é esperar que o banco compense uma lógica mal desenhada.
Se o fluxo:
- lê demais antes de decidir
- espalha decisão entre vários serviços
- depende de uma janela longa entre ler, decidir e gravar
o banco pode ajudar, mas talvez o problema real seja modelagem do processo.
Às vezes a melhor resposta não é aumentar lock.
É reduzir disputa, serializar por chave ou mudar o fluxo.
Exemplo simples
Imagine saldo de conta em 100.
Duas transações querem debitar 80.
Fluxo ingênuo:
- transação A lê
100 - transação B lê
100 - as duas concluem que podem debitar
- ambas gravam novo valor
Dependendo de como isso foi feito, você pode ter:
- saldo incorreto
- update perdido
- regra de negócio quebrada
Fluxo melhor depende do caso, mas pode ser algo como:
- update atômico condicionado
- lock na linha durante a decisão crítica
- transação com verificação coerente até a escrita final
O ponto importante não é decorar qual SQL usar.
É entender que a regra “saldo não pode ficar inválido” precisa ser protegida no ponto da disputa.
Erros comuns
- Fazer select e depois update como se ninguém mais pudesse ler o mesmo valor.
- Tratar transação como selo mágico sem pensar em isolamento e contenção.
- Colocar lock em excesso e derrubar throughput.
- Ignorar número de linhas afetadas em operação condicional.
- Resolver no frontend ou no código de aplicação algo que só fica realmente correto no armazenamento.
Como um senior pensa
Quem tem mais experiência normalmente pergunta:
onde exatamente a disputa acontece e qual a menor garantia que mantém essa regra verdadeira?
Essa pergunta é ótima porque evita dois extremos:
- solução fraca demais
- solução cara demais
Em banco, senioridade aparece muito nisso.
Não em falar nomes difíceis.
Mas em saber quando um update atômico basta, quando a transação precisa ser mais rígida e quando o desenho inteiro da operação merece mudar.
O que o entrevistador quer ver
Em entrevista, o avaliador quer ver se você entende concorrência como problema de corretude no dado.
Sinais bons:
- você nomeia a invariável
- reconhece read/decide/write perigoso
- fala de operação atômica, transação e lock com critério
- menciona custo de contenção e throughput
Uma resposta forte pode soar assim:
“Quando duas transações disputam o mesmo dado, eu primeiro nomeio a regra que não pode quebrar. Se couber em uma escrita condicional ou atômica, prefiro esse caminho. Se a decisão atravessa mais de um passo, avalio transação e isolamento. E só uso lock mais pesado quando a disputa realmente exige.”
Concorrência no banco não é detalhe de implementação. É onde muita regra de negócio vive ou morre.
Quando a proteção certa fica no lugar certo, a aplicação para de depender de timing favorável.
Resumo rápido
O que vale manter na cabeça
- Concorrência no banco é sobre preservar invariáveis quando duas transações disputam o mesmo dado.
- Select seguido de update sem proteção costuma ser o caminho mais curto para update perdido e decisão errada.
- Operação atômica, transação, lock e isolamento resolvem problemas diferentes e têm custo diferente.
- A escolha certa começa pela regra de negócio que não pode quebrar, não pela ferramenta preferida do time.
Checklist de pratica
Use isto ao responder
- Consigo reconhecer um fluxo de leitura seguida de escrita que fica perigoso sob concorrência?
- Sei diferenciar quando operação atômica basta e quando preciso de transação ou lock?
- Consigo explicar o custo de segurar lock demais em throughput e latência?
- Sei responder em entrevista como proteger estoque, saldo ou reserva sem falar em soluções soltas?
Você concluiu este artigo
Compartilhar esta página
Copie o link manualmente no campo abaixo.