O que e uma transação?

Uma transação e um conjunto de operações executadas como uma unidade atômica e indivisível.

Uma transação e uma sequência de operações de banco de dados tratadas como uma unidade lógica. Ou todas as operações são executadas com sucesso e o resultado e permanente, ou nenhuma delas produz efeito, o banco volta ao estado anterior. Esse comportamento e crítico para operações como transferências bancárias: debitar de uma conta e creditar em outra são duas operações separadas, mas precisam acontecer juntas ou nenhuma deve acontecer. Sem transações, uma falha entre o débito e o crédito criária dinheiro do nada ou o fária desaparecer. Transações existem precisamente para garantir que esse tipo de inconsistência nunca ocorra em sistemas que dependem de integridade de dados.

Atomicidade

Tudo ou nada, a transação inteira e confirmada ou desfeita, nunca parcialmente.

Atomicidade e a garantia de que uma transação e indivisível. Se qualquer operação dentro da transação falhar, todas as operações anteriores são desfeitas automaticamente pelo banco. O mecanismo por tras da atomicidade e o log de undo, o banco registra o estado anterior de cada dado modificado antes de modificar. Se a transação precisar ser revertida, o banco usa esse log para desfazer as mudancas. No PostgreSQL, isso e implementado via WAL, Write-Ahead Log. Atomicidade elimina estados inconsistentes parciais. No SQL, as transações são demarcadas com BEGIN, COMMIT para confirmar e ROLLBACK para desfazer.

Consistência

O banco passa de um estado valido para outro estado valido, restrições são sempre mantidas.

Consistência garante que uma transação só pode levar o banco de um estado valido para outro estado valido. Restrições de integridade, chaves estrangeiras, constraints, checks, são verificadas ao final da transação. Se qualquer restrição for violada, a transação e revertida. Isso significa que o banco nunca fica num estado onde uma chave estrangeira aponta para um registro inexistente, ou onde um saldo de conta fica negativo quando há uma constraint proibindo isso. A consistência depende tanto do banco, que enforca as constraints, quanto da aplicação, que define regras de negócio que o banco não conhece, como "uma reserva não pode ter data de saida anterior a data de entrada".

Isolamento

Transações concorrentes não interferem entre si, com diferentes níveis de garantia.

Isolamento define como transações concorrentes interagem. O nível mais alto, Serializable, garante que o resultado de transações concorrentes e idêntico ao de transações executadas em serie, uma por vez. O nível mais baixo, Read Uncommitted, permite leituras sujas de dados ainda não commitados. Entre os dois extremos existem Read Committed, padrão no PostgreSQL, e Repeatable Read. Cada nível previne diferentes fenômenos: dirty read, non-repeatable read e phantom read. Maior isolamento significa maior segurança mas menor throughput. A maioria das aplicações usa Read Committed como padrão e eleva para Serializable apenas em operações críticas como transferências financeiras.

Durabilidade

Dados commitados sobrevivem a falhas, WAL e persistência em disco garantem isso.

Durabilidade garante que uma vez que o COMMIT e confirmado para o cliente, os dados estão persistidos e não serao perdidos mesmo que o servidor caia imediatamente depois. Isso e implementado via Write-Ahead Log: antes de modificar qualquer página de dados em disco, o banco escreve a operação no WAL. Se o servidor cair, na reinicialização o banco repete as operações do WAL para recuperar o estado consistente mais recente. Em sistemas com réplicação, durabilidade pode exigir que o commit seja confirmado em N réplicas antes de retornar sucesso ao cliente, o que adiciona latência mas garante sobrevivência a falhas de hardware.

Niveis de isolamento e fenômenos

Cada nível previne fenômenos específicos, a escolha certa depende do caso de uso.

Dirty read ocorre quando uma transação le dados modificados por outra transação ainda não commitada. Read Uncommitted permite isso, os outros níveis previnem. Non-repeatable read ocorre quando a mesma query retorna resultados diferentes em duas leituras dentro da mesma transação, pois outra transação commitou uma modificação entre as duas leituras. Repeatable Read e Serializable previnem isso. Phantom read ocorre quando a mesma query retorna linhas adicionais numa segunda execução porque outra transação inseriu linhas novas. Apenas Serializable previne phantom reads completamente. No PostgreSQL, o nível Repeatable Read também previne phantom reads via MVCC, o que e mais restritivo que o SQL padrão exige.

MVCC, Multi-Version Concurrency Control

PostgreSQL cria versões de linhas para permitir leituras sem bloquear escritas.

MVCC e o mecanismo que permite que leitores e escritores não se bloqueiem mutuamente no PostgreSQL. Em vez de bloquear uma linha ao le-la, o banco mantem múltiplas versões da mesma linha. Uma transação de leitura ve sempre um snapshot consistente do banco no momento em que a transação começou, mesmo que outras transações estejam modificando dados simultaneamente. Escritas criam versões novas das linhas; versões antigas são mantidas até que nenhuma transação ativa precise delas, momento em que o VACUUM as remove. MVCC e a razao pela qual o PostgreSQL tem excelente performance de leitura concorrente, sem os locks de leitura que degradam throughput em outros bancos.

Deadlocks

Duas transações se bloqueiam mutuamente esperando recursos que a outra possui.

Um deadlock ocorre quando a transação A espera por um recurso bloqueado pela transação B, enquanto a transação B espera por um recurso bloqueado pela transação A. Nenhuma das duas pode prosseguir. O banco detecta deadlocks periodicamente e mata uma das transações, a vitima, com um erro. A aplicação deve estar preparada para capturar esse erro e repetir a transação. Para minimizar deadlocks, a melhor prática e sempre adquirir locks na mesma ordem em todas as transações. Por exemplo, sempre bloquear a tabela de contas em ordem crescente de ID. Isso evita o ciclo de dependência que cria o deadlock.

Transações distribuídas e SAGA

Em microservicos, transações ACID clássicas não funcionam, o padrão SAGA resolve isso.

Em arquiteturas de microservicos, cada serviço tem seu próprio banco. Não e possível fazer um BEGIN/COMMIT clássico que abrange múltiplos bancos de forma confiável. O protocolo Two-Phase Commit (2PC) existe para isso mas e fragil e gera acoplamento. O padrão SAGA e a alternativa mais usada em microservicos. Em vez de uma transação distribuída, a SAGA e uma sequência de transações locais, cada uma publicando um evento que aciona o próximo passo. Se um passo falha, transações compensatorias são executadas para desfazer os passos anteriores. SAGA não oferece isolamento forte, mas e resiliente, escalável e funciona bem em sistemas assíncronos baseados em eventos.

Resumo final

ACID e a base da confiabilidade em bancos de dados, entender cada letra e essencial.

Transações são o mecanismo que garante integridade em operações críticas. Atomicidade garante tudo ou nada. Consistência garante que restrições são sempre mantidas. Isolamento define como transações concorrentes interagem, com trade-offs de performance e segurança. Durabilidade garante que dados commitados sobrevivem a falhas. MVCC permite alta concorrência sem bloquear leituras. Deadlocks são inevitáveis em sistemas com alta concorrência, a aplicação deve tratar. Em microservicos, o padrão SAGA substitui transações distribuídas clássicas com sequências de transações locais e compensação. Entender esses conceitos e o que permite construir sistemas financeiros, de reservas e de pagamentos que funcionam corretamente mesmo sob falhas e alta carga.

Tutoriais em Video

Conceitos-chave

Atomicidade

Tudo ou nada, a transação inteira e confirmada ou desfeita, nunca parcialmente

Consistência

O banco passa de um estado valido para outro valido, restrições de integridade são mantidas

Isolamento

Transações concorrentes não interferem entre si, níveis: Read Uncommitted, Read Committed, Repeatable Read, Serializable

Durabilidade

Dados commitados sobrevivem a falhas, WAL Write-Ahead Log e persistência em disco

Deadlock

Duas transações se bloqueiam mutuamente esperando recursos que a outra possui

MVCC

Multi-Version Concurrency Control, PostgreSQL cria versões de linhas para permitir leituras sem bloquear escritas

Transações no Instagram

@bytebytego

Reels

@bytebytego

Facebook

Transações no X (Twitter)

@mjovanovictech

Software architecture patterns explained

Ver post completo no X →
@mjovanovictech

System design best practices

Ver post completo no X →
@mjovanovictech

Domain events and distributed systems

Ver post completo no X →
@mjovanovictech

Building resilient distributed systems

Ver post completo no X →
@mjovanovictech

Microservices vs monolith decisions

Ver post completo no X →
@mjovanovictech

Software design fundamentals

Ver post completo no X →

O que devs dizem

Pedro A. ★★★★★

Aprendi ACID na teoria mas só entendi de verdade quando debuguei um deadlock em produção. Duas operações de pagamento bloqueando uma a outra. Resolver exigiu entender como os locks funcionam e mudar a ordem de acesso.

Juliana C. ★★★★★

MVCC foi o que me fez entender por que o PostgreSQL e tao performatico com leituras concorrentes. Não precisa bloquear leituras para garantir consistência. Isso muda tudo para APIs com muitas leituras simultaneas.

Carlos H. ★★★★☆

Implementar o padrão SAGA pela primeira vez foi desafiador, mas a lógica de compensação e elegante. Especialmente com eventos e Kafka, fica muito natural modelar fluxos de negócio complexos sem transações distribuídas frageis.