15 de agosto de 2026 • Java

12 - Gerenciadores de Transações Spring

Introdução

Em aplicações empresariais, as transações são essenciais para garantir que um grupo de operações ou seja bem-sucedido completamente ou falhe completamente.

Spring oferece uma poderosa abstração de gerenciamento de transações que separa o tratamento de transações da lógica de negócio, permitindo que os desenvolvedores se concentrem na funcionalidade da aplicação em vez do código repetitivo (boilerplate) de transação.

Spring suporta duas abordagens principais:

  • Gerenciamento Programático de Transações
  • Gerenciamento Declarativo de Transações

Ele também fornece diferentes implementações de transaction manager dependendo da tecnologia utilizada.


Por que Precisamos de Transaction Managers?

Sem um transaction manager, os desenvolvedores precisariam:

  1. Abrir uma transação
  2. Executar a lógica de negócio
  3. Realizar commit se for bem-sucedido
  4. Realizar rollback se ocorrer um erro
  5. Fechar recursos

Exemplo sem Spring:

Connection connection = dataSource.getConnection();

try {
    connection.setAutoCommit(false);

    // Business logic

    connection.commit();
} catch (Exception ex) {
    connection.rollback();
} finally {
    connection.close();
}

Problemas com esta abordagem:

  • Código repetitivo
  • Difícil de manter
  • Propenso a erros
  • A lógica de negócio torna-se acoplada ao gerenciamento de transações
  • Difícil de lidar com cenários de transação complexos

Spring resolve esses problemas fornecendo uma abstração de transação.


O que é um Transaction Manager?

Um Transaction Manager é um componente Spring responsável por controlar transações.

Suas principais responsabilidades incluem:

  • Iniciar transações
  • Realizar commit de transações
  • Realizar rollback de transações
  • Gerenciar limites de transação
  • Coordenar recursos transacionais
  • Integrar transações com tecnologias de persistência

A abstração central do Spring é:

PlatformTransactionManager

Conceitualmente:

Application
    |
    v
Transaction Manager
    |
    +---- Begin Transaction
    |
    +---- Execute Business Logic
    |
    +---- Commit
    |       or
    +---- Rollback

A interface PlatformTransactionManager fornece as operações fundamentais de transação:

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(
        TransactionDefinition definition
    );

    void commit(TransactionStatus status);

    void rollback(TransactionStatus status);
}

Implementações de Transaction Manager

Spring oferece diferentes implementações de transaction manager dependendo da tecnologia.

Exemplos comuns incluem:

  • DataSourceTransactionManager
  • JpaTransactionManager
  • JtaTransactionManager
  • R2dbcTransactionManager

DataSourceTransactionManager

DataSourceTransactionManager é usado para aplicações que trabalham diretamente com JDBC.

Exemplo:

@Bean
public PlatformTransactionManager transactionManager(
        DataSource dataSource) {

    return new DataSourceTransactionManager(dataSource);
}

Arquitetura típica:

Spring
   |
   v
DataSourceTransactionManager
   |
   v
JDBC
   |
   v
Database

Quando Usar

Use-o quando:

  • Trabalhando diretamente com JDBC
  • Usando JdbcTemplate
  • Não utilizando JPA/Hibernate

Vantagens

  • Leve
  • Simples
  • Bom controle sobre transações JDBC

Desvantagens

  • Específico para JDBC
  • Não destinado ao gerenciamento de entidades JPA

JpaTransactionManager

JpaTransactionManager é comumente usado com:

  • Spring Data JPA
  • JPA
  • Hibernate

Exemplo:

@Bean
public PlatformTransactionManager transactionManager(
        EntityManagerFactory entityManagerFactory) {

    return new JpaTransactionManager(entityManagerFactory);
}

Arquitetura típica:

Spring
   |
   v
JpaTransactionManager
   |
   v
JPA / Hibernate
   |
   v
Database

Em aplicações Spring Boot que utilizam Spring Data JPA, o Spring Boot geralmente configura a infraestrutura de transações necessária automaticamente.

Vantagens

  • Integra-se com JPA
  • Integra-se com Hibernate
  • Gerencia EntityManager
  • Suporta sincronização de transações
  • Funciona naturalmente com @Transactional

Quando Usar

Use-o quando sua aplicação utiliza:

Spring Data JPA
        +
Hibernate
        +
Relational Database

Esta é uma das configurações de transaction manager mais comuns em aplicações Spring.


JtaTransactionManager

JtaTransactionManager é projetado para transações baseadas em JTA e cenários de transações distribuídas.

Ele pode coordenar transações envolvendo múltiplos recursos.

Por exemplo:

Application
     |
     v
JtaTransactionManager
     |
     +---- Database A
     |
     +---- Database B
     |
     +---- Message Broker

Este tipo de transação é às vezes chamado de transação distribuída.

Quando Usar

Casos de uso típicos incluem:

  • Múltiplos bancos de dados
  • Múltiplos recursos transacionais
  • Aplicações empresariais legadas
  • Transações XA

Vantagens

  • Pode coordenar múltiplos recursos transacionais
  • Suporta transações distribuídas

Desvantagens

  • Mais complexo
  • Maior overhead operacional
  • Pode afetar negativamente o desempenho
  • Geralmente desnecessário para arquiteturas de microserviços modernas

R2dbcTransactionManager

Para aplicações reativas usando R2DBC, o Spring oferece:

R2dbcTransactionManager

Exemplo:

@Bean
ReactiveTransactionManager transactionManager(
        ConnectionFactory connectionFactory) {

    return new R2dbcTransactionManager(connectionFactory);
}

Arquitetura típica:

Spring WebFlux
      |
      v
Reactive Transaction Manager
      |
      v
R2DBC
      |
      v
Database

Isso é usado com tipos reativos como:

Mono<T>
Flux<T>

Gerenciamento Programático de Transações

O que é Gerenciamento Programático de Transações?

Gerenciamento programático de transações significa que o desenvolvedor controla explicitamente o comportamento da transação através de código.

O desenvolvedor decide:

  • Quando a transação começa
  • Quando ela faz commit
  • Quando ela faz rollback
  • Qual configuração de transação é usada

Spring oferece dois mecanismos importantes:

  • PlatformTransactionManager
  • TransactionTemplate

Transações Programáticas com TransactionTemplate

TransactionTemplate é uma das maneiras mais fáceis de implementar transações programáticas.

Exemplo:

@Service
public class PaymentService {

    private final TransactionTemplate transactionTemplate;

    public PaymentService(
            PlatformTransactionManager transactionManager) {

        this.transactionTemplate =
                new TransactionTemplate(transactionManager);
    }

    public void processPayment() {

        transactionTemplate.execute(status -> {

            // Business logic

            return null;
        });
    }
}

Spring gerencia:

Begin
  |
  v
Business Logic
  |
  +---- Success ---> Commit
  |
  +---- Exception --> Rollback

Rollback Programático

Você pode marcar explicitamente uma transação para rollback:

transactionTemplate.execute(status -> {

    try {

        // Business logic

    } catch (Exception ex) {

        status.setRollbackOnly();
    }

    return null;
});

A transação será revertida (rollback) quando o callback da transação terminar.


Configuração Programática de Transações

Você pode configurar propriedades de transação usando TransactionTemplate.

Por exemplo:

transactionTemplate.setTimeout(30);
transactionTemplate.setReadOnly(true);

Você também pode configurar a propagação:

transactionTemplate.setPropagationBehavior(
        TransactionDefinition.PROPAGATION_REQUIRES_NEW
);

E isolamento:

transactionTemplate.setIsolationLevel(
        TransactionDefinition.ISOLATION_READ_COMMITTED
);

Isso dá às transações programáticas um alto nível de controle.


Vantagens das Transações Programáticas

Controle Granular

Você decide exatamente onde a transação começa e termina.

transactionTemplate.execute(status -> {

    // Transaction boundary is explicit

    return null;
});

Comportamento Dinâmico da Transação

As configurações de transação podem ser configuradas programaticamente.

Por exemplo:

transactionTemplate.setTimeout(30);

ou:

transactionTemplate.setReadOnly(true);

Útil para Fluxos de Trabalho Complexos

Transações programáticas podem ser úteis quando os limites de transação dependem de condições de tempo de execução.

Exemplo:

if condition A
    Transaction A

else
    Transaction B

Desvantagens das Transações Programáticas

Mais Boilerplate (Código Repetitivo)

A lógica da transação é misturada com o código da aplicação.

transactionTemplate.execute(status -> {

    // Transaction-related code

    // Business logic

    return null;
});

Mais Difícil de Manter

Se muitos métodos utilizarem transações programáticas, a aplicação pode se tornar repetitiva.


A Lógica de Negócio Pode se Tornar Acoplada às Transações

Em vez de:

@Transactional
public void processOrder() {
}

você pode ter:

transactionTemplate.execute(status -> {

    processOrder();

    return null;
});

A infraestrutura de transação torna-se mais visível no código de negócio.


Quando Você Deve Usar Transações Programáticas?

O gerenciamento programático de transações é útil quando:

  • Os limites de transação são dinâmicos
  • Controle de transação avançado é necessário
  • Comportamentos de transação diferentes são necessários dentro de um método
  • Lógica de rollback condicional é necessária
  • Transações declarativas não são flexíveis o suficiente

Para a maioria das operações padrão da camada de serviço, as transações declarativas são geralmente preferíveis.


Gerenciamento Declarativo de Transações

O que é Gerenciamento Declarativo de Transações?

O gerenciamento declarativo de transações permite que os desenvolvedores definam o comportamento da transação sem controlar manualmente o ciclo de vida da transação.

A abordagem mais comum é:

@Transactional

Exemplo:

@Service
public class AccountService {

    @Transactional
    public void transferMoney(
            Long from,
            Long to,
            BigDecimal amount) {

        withdraw(from, amount);
        deposit(to, amount);
    }
}

Spring gerencia automaticamente:

  • Criação da transação
  • Commit
  • Rollback
  • Sincronização da transação
  • Propagação da transação
  • Isolamento
  • Ciclo de vida da transação

Como as Transações Declarativas Funcionam

O gerenciamento declarativo de transações depende fortemente de proxies Spring AOP.

Considere:

@Transactional
public void transferMoney() {
}

Spring cria um proxy em torno do bean.

Conceitualmente:

Client
   |
   v
Spring Proxy
   |
   +---- Begin Transaction
   |
   v
Business Method
   |
   +---- Success ---> Commit
   |
   +---- Exception --> Rollback

O proxy interage com o transaction manager configurado.

Por exemplo:

@Transactional
      |
      v
Spring AOP Proxy
      |
      v
Transaction Manager
      |
      v
Database

Exemplo de Transação Declarativa

@Service
public class OrderService {

    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @Transactional
    public void createOrder(Order order) {

        orderRepository.save(order);

        // Additional database operations
    }
}

Spring inicia automaticamente a transação antes de executar o método.

Se o método terminar com sucesso:

Commit

Se uma exceção apropriada causar rollback:

Rollback

Configuração de Transação Declarativa

Em aplicações Spring Boot modernas, o gerenciamento de transações é frequentemente configurado automaticamente.

Por exemplo, ao usar:

Spring Boot
    +
Spring Data JPA
    +
Hibernate

Spring Boot pode configurar automaticamente a infraestrutura de transações necessária.

O gerenciamento explícito de transações também pode ser habilitado usando:

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
}

Em muitas aplicações Spring Boot, no entanto, adicionar explicitamente @EnableTransactionManagement é desnecessário porque o Boot fornece a auto-configuração necessária.


Vantagens das Transações Declarativas

Código Mais Limpo

A lógica de negócio permanece focada na operação de negócio.

@Transactional
public void processOrder() {
    // Business logic
}

Menos Boilerplate (Código Repetitivo)

Você não precisa:

begin
commit
rollback
close

Manutenção Mais Fácil

O comportamento da transação é declarado diretamente no método.


Melhor Legibilidade

Os desenvolvedores podem ver imediatamente que um método é transacional:

@Transactional
public void transferMoney() {
}

Desvantagens das Transações Declarativas

Limitações do Proxy

Transações declarativas são geralmente implementadas através de proxies Spring.

Isso cria uma limitação importante chamada self-invocation (auto-invocação).

Exemplo:

@Service
public class UserService {

    public void methodA() {
        methodB();
    }

    @Transactional
    public void methodB() {
        // Transaction
    }
}

Chamando:

methodA();

não ativa necessariamente o proxy transacional para methodB().

A razão é que a chamada ocorre internamente dentro do mesmo objeto.

Conceitualmente:

External Caller
      |
      v
Spring Proxy
      |
      v
methodA()
      |
      v
methodB()

A chamada de methodA() para methodB() não passa pelo proxy novamente.


Transações Programáticas vs Declarativas

CaracterísticaProgramáticaDeclarativa
Facilidade de UsoBaixaAlta
BoilerplateAltoBaixo
LegibilidadeMédiaAlta
FlexibilidadeMuito AltaAlta
ManutençãoMais DifícilMais Fácil
Controle da TransaçãoExplícitoImplícito
RecomendadoCasos EspeciaisMaioria das Aplicações

Múltiplos Transaction Managers

Uma aplicação pode ter mais de um transaction manager.

Por exemplo, uma aplicação pode usar dois bancos de dados:

Application
    |
    +---- Database A
    |
    +---- Database B

Cada banco de dados pode ter sua própria infraestrutura de transação.

Exemplo:

@Bean
public PlatformTransactionManager userTransactionManager(
        EntityManagerFactory userEntityManagerFactory) {

    return new JpaTransactionManager(
            userEntityManagerFactory
    );
}

E:

@Bean
public PlatformTransactionManager auditTransactionManager(
        EntityManagerFactory auditEntityManagerFactory) {

    return new JpaTransactionManager(
            auditEntityManagerFactory
    );
}

Você pode selecionar explicitamente um transaction manager:

@Transactional("auditTransactionManager")
public void saveAudit() {
}

Isso diz ao Spring qual transaction manager deve controlar a transação.


TransactionSynchronizationManager

Um componente interno importante do Spring é:

TransactionSynchronizationManager

Ele ajuda o Spring a associar recursos transacionais ao contexto de execução atual.

Ele pode gerenciar recursos como:

  • Conexões JDBC
  • EntityManagers
  • Callbacks de sincronização de transação
  • Estado relacionado à transação

Conceitualmente:

Application Thread
       |
       v
TransactionSynchronizationManager
       |
       +---- EntityManager
       |
       +---- JDBC Connection
       |
       +---- Transaction State

Este mecanismo é importante para permitir que diferentes componentes Spring participem da mesma transação.


Transaction Manager e @Transactional

É importante entender a relação entre esses dois conceitos.

Eles não são a mesma coisa.

@Transactional declara o comportamento da transação:

@Transactional
public void saveOrder() {
}

O Transaction Manager realiza o gerenciamento real da transação.

@Transactional
      |
      v
Spring AOP Proxy
      |
      v
Transaction Manager
      |
      v
Database

Então:

@Transactional
        =
Configuração/declaração da transação

Transaction Manager
        =
Execução/infraestrutura da transação

Transaction Manager e Propagação

Transaction managers também participam da propagação de transações.

Por exemplo:

@Transactional(
    propagation = Propagation.REQUIRES_NEW
)

O transaction manager determina como a transação atual deve ser tratada.

Por exemplo:

Transaction A
      |
      v
Service A
      |
      v
REQUIRES_NEW
      |
      v
Transaction B

A Transação B é executada independentemente da Transação A.

Esta é uma das razões pelas quais entender os transaction managers é importante antes de estudar a propagação de transações em profundidade.


Transaction Manager e Isolamento

Transaction managers também aplicam configurações de isolamento.

Exemplo:

@Transactional(
    isolation = Isolation.READ_COMMITTED
)
public void processOrder() {
}

O transaction manager comunica a configuração de transação solicitada ao recurso transacional subjacente.

Níveis de isolamento comuns incluem:

READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE

O comportamento real depende do banco de dados subjacente e da implementação da transação.


Transaction Manager e Transações Somente Leitura

Uma transação pode ser declarada como somente leitura:

@Transactional(readOnly = true)
public List<User> findUsers() {
    return userRepository.findAll();
}

Isso comunica que a transação é destinada à leitura de dados.

Dependendo da tecnologia de persistência, banco de dados e configuração, transações somente leitura podem fornecer otimizações e ajudar a prevenir escritas não intencionais.


Transaction Manager e Timeouts

Transaction managers também podem impor timeouts de transação.

Usando transações declarativas:

@Transactional(timeout = 30)
public void processPayment() {
}

Isso significa que a transação não deve permanecer ativa indefinidamente.

Timeouts são particularmente importantes para evitar que transações de longa duração retenham:

  • Conexões de banco de dados
  • Locks
  • Recursos

por períodos excessivos.


Boas Práticas

Prefira Transações Declarativas

Para a maioria das operações da camada de serviço, use:

@Transactional

em vez de gerenciar transações manualmente.


Coloque Limites de Transação na Camada de Serviço

Um padrão comum é:

Controller
    |
    v
Service
    |
    +---- @Transactional
    |
    v
Repository

Exemplo:

@Service
public class OrderService {

    @Transactional
    public void createOrder(Order order) {

        orderRepository.save(order);
        paymentRepository.save(order.getPayment());
    }
}

A camada de serviço geralmente representa a operação de negócio que precisa ser atômica.


Mantenha as Transações Pequenas

Evite transações desnecessariamente longas.

Bom:

@Transactional
public void saveOrder() {
    orderRepository.save(order);
}

Potencialmente problemático:

@Transactional
public void processLargeBatch() {

    // Milhares de operações de banco de dados
    // Chamadas a APIs externas
    // Cálculos longos
    // Processamento de arquivos
}

Transações longas podem reter recursos do banco de dados e locks por muito tempo.


Evite Chamadas a APIs Externas Dentro de Transações

Evite:

@Transactional
public void processOrder() {

    paymentGateway.call();

    orderRepository.save(order);
}

Se a API externa demorar muito para responder, a transação do banco de dados pode permanecer aberta desnecessariamente.

Uma arquitetura melhor pode separar a comunicação externa da transação do banco de dados ou usar processamento assíncrono/orientado a eventos quando apropriado.


Entenda o Transaction Manager Subjacente

Ao depurar problemas de transação, é importante saber qual transaction manager está sendo usado.

Por exemplo:

Spring Data JPA
       |
       v
JpaTransactionManager
       |
       v
Hibernate
       |
       v
Database

Entender essa cadeia facilita o diagnóstico de problemas envolvendo:

  • Rollbacks
  • Propagação
  • Isolamento
  • Conexões
  • EntityManager
  • Contexto de persistência
  • Limites de transação

Erros Comuns

Erro 1: Assumir que @Transactional Cria a Transação Por Si Só

@Transactional é uma declaração.

O transaction manager é responsável por gerenciar a transação real.

@Transactional
      |
      v
Proxy
      |
      v
Transaction Manager
      |
      v
Transaction

Erro 2: Usar Transações Programáticas Em Todo Lugar

Transações programáticas fornecem controle, mas o uso excessivo cria complexidade desnecessária.

Prefira:

@Transactional

quando o comportamento da transação é simples.


Erro 3: Ignorar o Comportamento do Proxy

Lembre-se que as transações declarativas do Spring geralmente dependem de proxies.

Portanto, a self-invocation pode impedir que o interceptor transacional seja acionado.


Erro 4: Tornar as Transações Muito Grandes

Transações grandes podem levar a:

  • Locks de banco de dados de longa duração
  • Esgotamento de conexões
  • Aumento de contenção
  • Baixo desempenho
  • Cenários de rollback difíceis

Arquitetura Recomendada

Uma arquitetura comum do Spring Boot se parece com:

Client
  |
  v
REST Controller
  |
  v
Service Layer
  |
  +---- @Transactional
  |
  v
Transaction Manager
  |
  v
Repository Layer
  |
  v
JPA / Hibernate
  |
  v
Database

Exemplo:

@RestController
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping("/orders")
    public void createOrder(@RequestBody Order order) {
        orderService.createOrder(order);
    }
}

Serviço:

@Service
public class OrderService {

    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @Transactional
    public void createOrder(Order order) {

        orderRepository.save(order);

        // Other database operations
    }
}

O controller não precisa saber como a transação funciona.

O serviço define o limite da transação de negócio.


Resumo

Spring Transaction Managers fornecem a infraestrutura necessária para gerenciar transações em aplicações Spring.

Os conceitos mais importantes são:

  • PlatformTransactionManager é a principal abstração de transação do Spring.
  • JpaTransactionManager é comumente usado com JPA e Hibernate.
  • DataSourceTransactionManager é usado para aplicações baseadas em JDBC.
  • JtaTransactionManager suporta transações distribuídas/JTA.
  • R2dbcTransactionManager é usado para transações de banco de dados reativas.
  • O gerenciamento programático de transações fornece controle explícito.
  • O gerenciamento declarativo de transações usa @Transactional e é a abordagem preferida para a maioria das aplicações.
  • Spring usa proxies AOP para implementar transações declarativas.
  • Múltiplos transaction managers podem existir na mesma aplicação.
  • TransactionSynchronizationManager ajuda a coordenar recursos transacionais.
  • Transaction managers trabalham em conjunto com configurações de propagação, isolamento, timeouts e somente leitura.
  • Os limites de transação são comumente colocados na camada de serviço.

A relação chave a ser lembrada é:

@Transactional
      |
      v
Spring AOP Proxy
      |
      v
Transaction Manager
      |
      v
Transaction
      |
      v
Database

Na maioria das aplicações Spring Boot, o desenvolvedor deve focar em definir o limite de transação correto com @Transactional, enquanto o Spring e o Transaction Manager configurado lidam com o ciclo de vida da transação.

← Voltar para o blog