11 - Anotação Transacional Spring
Tabela de Conteúdo
- Introdução
- O que é uma Transação?
- Princípios ACID
- Contexto Transacional
- Gerenciadores de Transações
- Spring
@Transactional - Comportamento de Rollback
- Propagação de Transações
- Níveis de Isolamento
- Timeouts de Transação
- Transações Somente Leitura
- Como o Spring Implementa Transações
- Limitações de
@Transactional - Vantagens e Desvantagens
- Melhores Práticas
- Resumo
Introdução
Em aplicações corporativas, a consistência dos dados é crítica.
Considere as seguintes operações:
- Transferências de dinheiro
- Criação de pedidos
- Atualizações de estoque
- Processamento de pagamentos
Se uma aplicação falhar no meio dessas operações, os dados podem se tornar inconsistentes.
Para resolver este problema, bancos de dados relacionais implementam transações, e o Spring fornece a anotação @Transactional para gerenciá-las automaticamente.
O que é uma Transação?
Uma transação é uma unidade lógica de trabalho que consiste em uma ou mais operações executadas como uma única unidade indivisível.
Uma transação tem apenas dois resultados possíveis:
- Commit → salva permanentemente todas as alterações.
- Rollback → desfaz todas as alterações.
Exemplo
Transferência bancária:
accountA.debit(100);
accountB.credit(100);
Ambas as operações devem ser bem-sucedidas juntas.
Se uma operação falhar:
Rollback de Tudo
Princípios ACID
ACID é um conjunto de propriedades que garantem a confiabilidade da transação.
A — Atomicidade
Uma transação é tudo-ou-nada.
Exemplo
accountA.debit(100);
accountB.credit(100);
Se a segunda operação falhar:
Rollback
Resultado:
Nenhuma alteração persistida
Benefício
Previne atualizações parciais.
C — Consistência
Uma transação deve mover o banco de dados de um estado válido para outro estado válido.
Exemplo
Regra de negócio:
balance >= 0
Esta operação é inválida:
account.setBalance(-500);
Resultado:
Transação Rejeitada
Benefício
Mantém regras e restrições de negócio.
I — Isolamento
Transações concorrentes não devem interferir umas nas outras.
Exemplo
Quantidade em estoque:
Estoque = 1
Dois usuários compram simultaneamente.
Sem isolamento:
Estoque = -1
Com isolamento adequado:
Estoque = 0
Benefício
Previne problemas de concorrência.
D — Durabilidade
Uma vez realizado o commit, os dados sobrevivem a falhas.
Exemplos:
- Reinicialização do servidor
- Queda de energia
- Falha da aplicação
COMMIT;
Após o commit:
Dados são armazenados permanentemente
Benefício
Garante persistência.
Contexto Transacional
O que é um Contexto Transacional?
Um contexto transacional é o escopo de execução no qual todas as operações de banco de dados participam da mesma transação.
Quando o Spring inicia uma transação:
Contexto Transacional Criado
Todas as operações de repositório executadas dentro desse contexto compartilham:
- Mesma transação
- Mesma conexão
- Mesmo commit
- Mesmo rollback
Exemplo
@Service
public class UserService {
@Transactional
public void createUser() {
userRepository.save(user);
roleRepository.save(role);
auditRepository.save(log);
}
}
Execução:
Contexto Transacional
├── userRepository.save()
├── roleRepository.save()
└── auditRepository.save()
Se qualquer operação falhar:
Rollback de Tudo
Por que é Importante?
Sem um contexto transacional:
Operação 1 → Commit
Operação 2 → Falha
Operação 3 → Nunca Executa
Resultado:
Dados Inconsistentes
Gerenciadores de Transações
O que é um Gerenciador de Transações?
O Gerenciador de Transações é responsável por:
- Iniciar transações
- Realizar commit de transações
- Realizar rollback de transações
O Spring delega o gerenciamento de transações a um PlatformTransactionManager.
PlatformTransactionManager
Interface de transação principal do Spring:
public interface PlatformTransactionManager {
}
O Spring seleciona automaticamente a implementação apropriada.
JpaTransactionManager
Usado com:
- JPA
- Hibernate
- Spring Data JPA
@Bean
public PlatformTransactionManager transactionManager(
EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
DataSourceTransactionManager
Usado com:
- JDBC
- JdbcTemplate
@Bean
public PlatformTransactionManager transactionManager(
DataSource ds) {
return new DataSourceTransactionManager(ds);
}
JtaTransactionManager
Usado para transações distribuídas.
Exemplos:
- Múltiplos bancos de dados
- Banco de dados + Mensageria
- Transações XA
Fluxo da Transação
@Transactional
↓
Proxy AOP do Spring
↓
PlatformTransactionManager
↓
Banco de Dados
Spring @Transactional
O que é @Transactional?
@Transactional é uma anotação do Spring que define limites transacionais.
O Spring automaticamente:
- Abre uma transação.
- Executa o método.
- Realiza commit em caso de sucesso.
- Realiza rollback em caso de falha.
Exemplo
@Service
public class TransferService {
@Transactional
public void transfer() {
accountA.debit(100);
accountB.credit(100);
}
}
Execução:
Abrir Transação
↓
Débito
↓
Crédito
↓
Commit
Falha:
Abrir Transação
↓
Débito
↓
Exceção
↓
Rollback
Transação no Nível da Classe
@Service
@Transactional
public class OrderService {
public void createOrder() {}
public void cancelOrder() {}
}
Todos os métodos públicos tornam-se transacionais.
Comportamento de Rollback
Regras Padrão de Rollback
O Spring faz rollback automaticamente para:
RuntimeException
Error
Exemplo:
@Transactional
public void process() {
throw new RuntimeException();
}
Resultado:
Rollback
Exceções Verificadas
Exceções verificadas (Checked Exceptions) requerem configuração explícita.
@Transactional(
rollbackFor = Exception.class
)
public void process() throws Exception {
throw new Exception();
}
Resultado:
Rollback
Propagação de Transações
A propagação define como um método transacional se comporta quando outra transação já existe.
REQUIRED (Padrão)
@Transactional(
propagation = Propagation.REQUIRED
)
Comportamento:
Transação Existente?
Sim → Juntar-se
Não → Criar Nova
Mais comumente usado.
REQUIRES_NEW
@Transactional(
propagation = Propagation.REQUIRES_NEW
)
Comportamento:
Suspender Transação Atual
Criar Nova Transação
Executar
Commit
Retomar Transação Original
Casos de uso comuns:
- Logs de auditoria
- Notificações
- Histórico de eventos
SUPPORTS
@Transactional(
propagation = Propagation.SUPPORTS
)
Comportamento:
Transação Existe?
Sim → Juntar-se
Não → Executar Sem Transação
Comum para operações de leitura.
NOT_SUPPORTED
@Transactional(
propagation = Propagation.NOT_SUPPORTED
)
Comportamento:
Suspender Transação Existente
Executar Sem Transação
Retomar Transação
Útil para:
- Chamadas de API externas
- Tarefas de longa duração
MANDATORY
@Transactional(
propagation = Propagation.MANDATORY
)
Requer uma transação existente.
Caso contrário:
IllegalTransactionStateException
NEVER
@Transactional(
propagation = Propagation.NEVER
)
Falha se uma transação existir.
NESTED
@Transactional(
propagation = Propagation.NESTED
)
Cria savepoints.
Transação Pai
│
├── Savepoint
│
└── Transação Aninhada
Permite rollback parcial.
O suporte do banco de dados varia.
Níveis de Isolamento
Os níveis de isolamento determinam como transações concorrentes interagem.
Problemas de Concorrência
Leitura Suja (Dirty Read)
Leitura de dados não confirmados.
T1 Atualiza Valor
T2 Lê Valor
T1 Faz Rollback
T2 leu dados inválidos.
Leitura Não Repetível (Non-Repeatable Read)
Ler a mesma linha duas vezes retorna valores diferentes.
T1 Lê Salário = 1000
T2 Atualiza Salário = 2000
T1 Lê Novamente = 2000
Leitura Fantasma (Phantom Read)
Uma consulta retorna linhas adicionais.
SELECT * FROM employees
Outra transação insere novas linhas.
A segunda consulta retorna resultados diferentes.
READ_UNCOMMITTED
Permite:
- Leituras Sujas
- Leituras Não Repetíveis
- Leituras Fantasmas
@Transactional(
isolation = Isolation.READ_UNCOMMITTED
)
Maior desempenho, menor consistência.
READ_COMMITTED
Previne:
- Leituras Sujas
Permite:
- Leituras Não Repetíveis
- Leituras Fantasmas
@Transactional(
isolation = Isolation.READ_COMMITTED
)
Mais comumente usado.
REPEATABLE_READ
Previne:
- Leituras Sujas
- Leituras Não Repetíveis
Permite:
- Leituras Fantasmas
@Transactional(
isolation = Isolation.REPEATABLE_READ
)
Padrão no MySQL InnoDB.
SERIALIZABLE
Previne:
- Leituras Sujas
- Leituras Não Repetíveis
- Leituras Fantasmas
@Transactional(
isolation = Isolation.SERIALIZABLE
)
Maior consistência.
Compromissos:
- Mais locks
- Menor throughput
Tabela Comparativa de Isolamento
| Nível de Isolamento | Leitura Suja | Leitura Não Repetível | Leitura Fantasma |
|---|---|---|---|
| READ_UNCOMMITTED | ❌ Permitido | ❌ Permitido | ❌ Permitido |
| READ_COMMITTED | ✅ Prevenido | ❌ Permitido | ❌ Permitido |
| REPEATABLE_READ | ✅ Prevenido | ✅ Prevenido | ❌ Permitido |
| SERIALIZABLE | ✅ Prevenido | ✅ Prevenido | ✅ Prevenido |
Timeouts de Transação
O que é um Timeout?
Define a duração máxima de uma transação.
Exemplo
@Transactional(timeout = 10)
public void processOrder() {
}
Significado:
Duração Máxima = 10 Segundos
Se excedido:
TransactionTimedOutException
Rollback
Por que Usar Timeouts?
Previne:
- Transações de longa duração
- Esgotamento de recursos
- Contenção de locks
- Deadlocks
Transações Somente Leitura
O que é uma Transação Somente Leitura?
Usado quando não são esperadas modificações de dados.
@Transactional(readOnly = true)
public User findUser(Long id) {
return repository.findById(id).orElseThrow();
}
Benefícios
Otimização do Hibernate
Fluxo normal:
Carregar Entidade
↓
Rastrear Alterações
↓
Flush
Somente leitura:
Carregar Entidade
↓
Sem Dirty Checking
Melhor Desempenho
Útil para:
@Transactional(readOnly = true)
public List<User> findAllUsers() {
return repository.findAll();
}
Benefícios:
- Menos memória
- Menos CPU
- Execução mais rápida
Nota Importante
Somente leitura nem sempre impede fisicamente as escritas.
O comportamento depende de:
- Banco de dados
- Driver JDBC
- Gerenciador de Transações
Como o Spring Implementa Transações
O Spring usa:
- AOP (Programação Orientada a Aspectos)
- Proxies Dinâmicos
Fluxo Interno
Cliente
↓
Proxy do Spring
↓
Abrir Transação
↓
Executar Método
↓
Commit / Rollback
Lógica equivalente:
beginTransaction();
try {
businessMethod();
commit();
}
catch(Exception ex) {
rollback();
}
Limitações de @Transactional
Métodos Privados
Não funciona.
@Transactional
private void save() {}
Razão:
Proxy Não Consegue Interceptar Métodos Privados
Auto Invocação
Não funciona.
@Service
public class UserService {
public void methodA() {
methodB();
}
@Transactional
public void methodB() {
}
}
Razão:
Chamada Ignora o Proxy do Spring
Vantagens
Simplicidade
@Transactional
public void save() {}
Menos Código Repetitivo
Não há necessidade de:
beginTransaction();
commit();
rollback();
Integração Transparente
Funciona com:
- JPA
- Hibernate
- JDBC
- Spring Data
Melhor Consistência
Ajuda a aplicar os princípios ACID.
Desvantagens
Transações Longas Podem Ser Perigosas
Pode causar:
- Locks
- Deadlocks
- Degradação de desempenho
Chamadas Externas Dentro de Transações
Exemplo ruim:
@Transactional
public void process() {
externalApi.call();
repository.save(entity);
}
A transação permanece aberta durante a chamada externa.
Curva de Aprendizagem
Desenvolvedores devem entender:
- Propagação
- Isolamento
- Regras de rollback
- Comportamento do proxy
Melhores Práticas
✅ Coloque @Transactional na camada de Serviço.
✅ Mantenha as transações curtas.
✅ Use readOnly = true sempre que possível.
✅ Evite chamadas remotas dentro de transações.
✅ Entenda a propagação antes de usar REQUIRES_NEW.
✅ Use timeouts para processos de longa duração.
❌ Não coloque @Transactional em Controllers.
❌ Não crie escopos transacionais grandes.
❌ Não ignore as implicações do nível de isolamento.
Resumo
| Tópico | Propósito |
|---|---|
| Transação | Unidade de trabalho |
| ACID | Garantias de confiabilidade |
| Contexto Transacional | Escopo transacional compartilhado |
| Gerenciador de Trans. | Controla o ciclo de vida da transação |
@Transactional | Gerenciamento de transações declarativo |
| Propagação | Regras de interação de transações |
| Isolamento | Controle de concorrência |
| Timeout | Duração máxima da transação |
| Somente Leitura | Otimização de consultas |
| Proxy AOP | Mecanismo de transação do Spring |
Compreender esses conceitos é essencial para construir aplicações Spring confiáveis, escaláveis e consistentes. Juntos, os princípios ACID, gerenciadores de transações, regras de propagação, níveis de isolamento e a anotação @Transactional formam a base do gerenciamento de transações no Spring Framework e Spring Boot.