E
Transactional no Spring: Propagação e Níveis de Isolamento
quinta-feira, 8 de janeiro de 202610 minutos

Transactional no Spring: Propagação e Níveis de Isolamento

#Spring#@Transactional#Transações#Propagação#Isolamento

Introdução à Anotação @Transactional no Spring

A anotação @Transactional é uma das principais características do framework Spring, usada para gerenciar transações de forma declarativa. Ela permite que os desenvolvedores especifiquem como e quando uma transação deve ser iniciada, comprometida ou revertida.

Neste tutorial, vamos explorar em profundidade a propagação e os níveis de isolamento das transações no Spring, fornecendo exemplos práticos para ilustrar cada conceito.

O que é Propagação de Transações?

A propagação de transações refere-se a como uma transação é tratada quando um método anotado com @Transactional é chamado a partir de outro método também anotado com @Transactional. O Spring fornece várias opções de propagação que definem o comportamento da transação em diferentes cenários.

Tipos de Propagação

A seguir, apresentamos os principais tipos de propagação disponíveis no Spring:

  • REQUIRED: Este é o comportamento padrão. Se uma transação já estiver em andamento, o método será executado dentro dessa transação. Caso contrário, uma nova transação será criada.
  • REQUIRES_NEW: Sempre cria uma nova transação, suspendendo a transação atual, se houver uma. Essa opção é útil quando você precisa garantir que uma operação seja realizada independentemente do estado da transação atual.
  • SUPPORTS: Se houver uma transação em andamento, o método será executado dentro dela. Caso contrário, será executado sem uma transação.
  • NOT_SUPPORTED: O método sempre será executado fora de uma transação, suspendendo qualquer transação em andamento.
  • MANDATORY: O método deve ser executado dentro de uma transação. Se não houver uma transação em andamento, uma exceção será lançada.
  • NEVER: O método deve ser executado fora de uma transação. Se houver uma transação em andamento, uma exceção será lançada.
  • NESTED: Se uma transação já estiver em andamento, o método será executado dentro de uma transação aninhada. Caso contrário, se não houver transação, uma nova será criada.

Exemplo de Propagação

Vamos considerar um cenário onde temos dois serviços: ServicoA e ServicoB. O ServicoA chama um método no ServicoB. Veja como podemos configurar a propagação:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ServicoA {
    @Transactional(propagation = Propagation.REQUIRED)
    public void metodoA() {
        // lógica do método A
        servicoB.metodoB();
    }
}

@Service
public class ServicoB {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void metodoB() {
        // lógica do método B
    }
}

No exemplo acima, se metodoA for chamado e uma transação já estiver em andamento, metodoB será executado em uma nova transação, independentemente do resultado de metodoA.

Níveis de Isolamento de Transações

Os níveis de isolamento definem como as transações interagem entre si. Eles controlam a visibilidade das alterações feitas por uma transação para outras transações. O Spring suporta os seguintes níveis de isolamento:

Tipos de Isolamento

  • DEFAULT: Usa o nível de isolamento padrão do banco de dados.
  • READ_UNCOMMITTED: Permite que uma transação leia dados não confirmados de outra transação. Isso pode levar a leituras sujas.
  • READ_COMMITTED: Garante que uma transação só possa ler dados confirmados. Evita leituras sujas, mas pode resultar em leituras não repetíveis.
  • REPEATABLE_READ: Garante que uma transação possa ler os mesmos dados várias vezes e obter o mesmo resultado. Isso evita leituras não repetíveis, mas pode levar a fantasmas.
  • SERIALIZABLE: O nível mais alto de isolamento, que garante que as transações sejam completamente isoladas uma da outra. Isso evita leituras sujas, leituras não repetíveis e fantasmas, mas pode impactar a performance.

Exemplo de Nível de Isolamento

Vamos agora adicionar um nível de isolamento ao nosso exemplo anterior:

import org.springframework.transaction.annotation.Isolation;

@Service
public class ServicoB {
    @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    public void metodoB() {
        // lógica do método B
    }
}

No código acima, o metodoB está configurado para usar o nível de isolamento READ_COMMITTED, garantindo que apenas dados confirmados sejam lidos.

Quando Usar Cada Tipo de Propagação e Isolamento

Escolher o tipo de propagação e nível de isolamento corretos depende do contexto da sua aplicação e dos requisitos de consistência de dados.

  • REQUIRED: Use quando você deseja que métodos sejam executados dentro da mesma transação, garantindo a atomicidade.
  • REQUIRES_NEW: Ideal para operações que não devem ser afetadas por uma transação pai, como registros de auditoria.
  • READ_COMMITTED: É um bom equilíbrio entre desempenho e consistência, evitando leituras sujas.
  • SERIALIZABLE: Use quando a integridade dos dados é crítica e você pode tolerar a perda de desempenho.

Conclusão

A anotação @Transactional no Spring é uma ferramenta poderosa para gerenciar transações de forma eficaz. Compreender a propagação e os níveis de isolamento é crucial para garantir a integridade e consistência dos dados em suas aplicações.

Experimente aplicar diferentes configurações de propagação e isolamento em seus serviços para ver como isso afeta o comportamento das transações e a performance da sua aplicação.

Call to Action

Se você deseja aprofundar seus conhecimentos sobre o Spring e transações, considere explorar a documentação oficial do Spring Framework e praticar com exemplos em seus projetos.

FAQ

O que acontece se uma exceção ocorrer em um método anotado com @Transactional?

Se uma exceção não verificada ocorrer, a transação será revertida automaticamente. Para exceções verificadas, você deve configurar a anotação para que a transação seja revertida.

Posso usar @Transactional em métodos privados?

Não, a anotação @Transactional deve ser aplicada em métodos públicos, pois o Spring usa proxies para aplicar a lógica de transação.

Qual é a diferença entre @Transactional e gerenciamento de transações programático?

A anotação @Transactional permite um gerenciamento declarativo, tornando o código mais limpo e fácil de manter, enquanto o gerenciamento programático exige mais código e pode ser mais propenso a erros.

Como posso testar métodos anotados com @Transactional?

Você pode usar frameworks de teste como JUnit e Spring Test para criar testes que verifiquem o comportamento das transações, garantindo que as operações sejam realizadas corretamente.

O que são transações aninhadas?

Transações aninhadas permitem que uma transação contenha outras transações. No Spring, isso é feito usando a propagação NESTED, permitindo que você reverta apenas a transação interna se necessário.


Author

Eridani Melo

Full Stack Developer