Tipos de Propagação de Transações no Spring

Introdução ao Gerenciamento de Transações Declarativas no Spring

O Spring Framework oferece suporte a gerenciamento de transações declarativo, permitindo que desenvolvedores controlem o comportamento das transações por meio de configurações. O comportamento de propagação de transação define como métodos executados dantro de um contexto de transação interagem com transações existentes. A seguir, estão detalhados os sete tipos de propagação suportados pelo Spring.

Tipos de Propagação e Exemplos de Código

Os tipos de propagação são definidos em uma enumeração dentro do framework. Aqui, exploramos cada um com exemplos práticos, reescritos para maior clareza.

REQUIRED (Padrão)

Se uma transação corrente existir, o método se junta a ela; caso contrário, uma nova transação é criada. Este é o comportamento padrão.

@Service
public class ServicoPedidos {

    @Transactional(propagation = Propagation.REQUIRED)
    public void efetuarPedido(Pedido pedido) {
        this.armazenarPedido(pedido);
        this.notificarCliente(pedido);
    }

    private void armazenarPedido(Pedido pedido) {
        // Simulação de persistência no banco de dados
    }

    private void notificarCliente(Pedido pedido) {
        // Simulação de envio de notificação
    }
}

Neste exemplo, o método efetuarPedido opera dentro de uma transação, e os métodos auxiliares são executados no mesmo escopo transacional.

SUPPORTS

O método participa de uma transação existente, se houver; caso contrário, executa sem transação.

@Service
public class ServicoMarketing {

    @Autowired
    private ServicoEmail servicoEmail;

    @Transactional(propagation = Propagation.SUPPORTS)
    public void enviarCampanhasEmail() {
        // Executa dentro de uma transação se disponível, senão sem transação.
        servicoEmail.dispararEmails();
    }
}

Quando chamado por um método transacional, este método adere à transação; de outra forma, age de forma não transacional.

MANDATORY

Exige uma transação existente. Se nenhuma transação estiver ativa, uma exceção é lançada.

@Service
public class ServicoPagamentos {

    @Transactional(propagation = Propagation.MANDATORY)
    public void registrarPagamento(Pagamento pagamento) {
        // Deve ser chamado dentro de uma transação; caso contrário, erro.
        repositorioPagamento.salvar(pagamento);
    }
}

Este método garante que só seja executado em um contexto transacional controlado por um invocador.

REQUIRES_NEW

Sempre inicia uma nova transação, suspendendo qualquer transação corrente.

@Service
public class ServicoCatalogo {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void atualizarProduto(Produto produto) {
        // Nova transação isolada; transações anteriores são pausadas.
        repositorioProduto.atualizar(produto);
    }
}

Útil para operações que necessitam isolamento completo, independentemente do contexto transacional do chamador.

NOT_SUPPORTED

Executa sem transação, suspendendo qualquer transação corrente.

@Service
public class ServicoRelatorios {

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void gerarRelatorio() {
        // Operação não transacional; transações existentes são pausadas.
        repositorioRelatorio.criar(new Relatorio());
    }
}

Ideal para tarefas de longa duração ou de leitura que não requerem atomicidade.

NEVER

Executa exclusivamente fora de uma transação. Se uma transação estiver ativa, lança uma exceção.

@Service
public class ServicoAuditoria {

    @Transactional(propagation = Propagation.NEVER)
    public void registrarAcao(Acao acao) {
        // Deve rodar sem transação; transações existentes causam erro.
        repositorioAuditoria.logar(acao);
    }
}

Assegura que o método nunca participe de transações, reforçando o design da aplicação.

NESTED

Se uma transação existir, executa em uma transação aninhada (ponto de salvamento); se não, comporta-se como REQUIRED.

@Service
public class ServicoUsuarios {

    @Transactional(propagation = Propagation.REQUIRED)
    public void cadastrarUsuario(Usuario usuario) {
        this.salvarUsuario(usuario);
        this.processarEtapaExtra(usuario);
    }

    @Transactional(propagation = Propagation.NESTED)
    public void processarEtapaExtra(Usuario usuario) {
        // Transação aninhada: pode ser revertida independentemente.
        repositorioExtra.persistir(usuario);
    }
}

Oferece flexibilidade para rollback parcial dentro de um escopo transacional maior.

Considerações de Implementação

A escolha do tipo de propagação afeta o comportamento transacional da aplicação. Fatores como isolamento de dados, desempenho e requisitos de integridade devem ser avaliados ao configurar anotações @Transactional.

O suporte a transações aninhadas pode variar conforme o gerenciador de transações utilizado, como o DataSourceTransactionManager para JDBC ou soluções JTA.

Tags: Spring Propagação de Transações java Gerenciamento de Transações Spring Framework

Publicado em 6-15 19:20 por Thomas