O que é atomicidade em banco de dados
Atomicidade é uma das quatro propriedades ACID em sistemas de banco de dados e significa simplesmente que uma transação deve ser executada por completo ou não ser executada de jeito nenhum. Nada de metade concluído, nada de operações pendentes que deixam o registro no limbo. Se um passo falha, o banco desfaz tudo automaticamente e devolve os dados ao estado anterior à transação. Achei que isso era óbvio quando comecei a trabalhar com SQL. Até um projeto meu em 2019 mostrar o contrário. Estávamos migrando dados de uma tabela legado para outra nova, usando uma transação manual com cerca de 47 mil linhas inseridas. A query principal funcionava perfeitamente. Porém, no final do lote, um erro de constraint única travou a operação. O banco deveria fazer rollback total. E fez. Porém, metade dos dados já haviam sido commitados anteriormente por um script anterior que eu não tinha percebido que também rodava no mesmo banco. A atomicidade protegeu a transação atual, mas o problema real estava na sobreposição de scripts que se ignoravam. Aprendi daí que atomicidade não resolve problemas de coordenação entre processos diferentes.
o que é atomicidade em banco de dados na prática
Na prática, atomicidade funciona através de logs de undofundo da operação. Cada modificação é registrada em um log transacional antes de qualquer compromisso. Se algo der errado durante a execução, o motor usa esse log para reverter cada ação na ordem inversa. Isso acontece em milissegundos na maioria dos bancos relacionais modernos. PostgreSQL, MySQL, Oracle, SQL Server todos fazem isso de forma transparente para você, desde que use transações corretamente. Muita gente esquece um detalhe importante. A atomicidade só se aplica dentro de uma única transação. Se você espalhar o mesmo fluxo em múltiplas transações separadas, cada uma vai garantir sua própria atomicidade, mas o resultado global pode ser inconsistente. Já vi desenvolvedores criar batches que pareciam seguros porque usavam BEGIN TRANSACTION em cada trecho, mas quando um batch falhava no meio, os batches anteriores já tinham confirmado suas alterações sem saber da falha futura. O resultado eram registros órfãos e dados duplicados espalhados por horas de trabalho pra consertar.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Outro ponto que pouca gente considera é que a atomicidade tem um custo. Cada operação precisa escrever no log antes de aplicar a mudança na tabela. Isso significa mais I/O e mais latência. Em cargas intensas de escrita, como processos de ETL que rodam dezenas de milhares de inserts por segundo, o log transacional pode virar gargalo. Uma solução que encontrei foi diminuir o tamanho dos batches e usar COMMIT intermediários controlados em vez de uma única transação gigantesca. Funciona quando você não precisa de atomicidade absoluta sobre todo o lote, mas garante que pelo menos grupos menores sejam atômicos. O trade-off é perder a garantia completa, mas ganha-se performance significativa. Se o seu cenário exige atomicidade rigorosa sobre operações distribuídas, ou serviços, aí a coisa complica. Transações distribuídas usam protocolos como two-phase commit, que adicionam complexidade e latência considerável. Às vezes vale mais a pena abandonar a atomicidade estrita e adotar padrões baseados em eventos com compensação, onde cada falha gera uma operação reversa manual ao invés de depender do mecanismo automático do banco.
O que muita documentação não mostra é que atomicidade depende inteiramente de como você estrutura suas queries. Usar autocommit ativado faz com que cada statement seja uma transação individual. Nesse modo, um INSERT falho não reverte um SELECT que rodou anteriormente na mesma conexão. Você precisa explicitamente abrir transações com BEGIN ou START TRANSACTION para que a atomicidade faça sentido no contexto que você espera. Sem isso, está basicamente dependendo do comportamento padrão do banco, que varia entre engines e configurações. Em resumo, atomicidade é um conceito simples na teoria mas cheio de armadilhas na execução. Ela garante que transações individuais sejam indivisíveis, mas não protege contra erros de design que fragmentam o fluxo em múltiplas transações. Conhecer esses limites evita dores de cabeça desnecessárias e ajuda a escolher a estratégia certa para cada tipo de operação.