O atributo Spring @Transactional funciona em um método privado?

Se eu tiver uma anotação @Transactional em um método privado em um bean Spring, a anotação terá algum efeito?

Se a anotação @Transactional estiver em um método público, ela funcionará e abrirá uma transação.

 public class Bean { public void doStuff() { doPrivateStuff(); } @Transactional private void doPrivateStuff() { } } ... Bean bean = (Bean)appContext.getBean("bean"); bean.doStuff(); 

A resposta é a sua pergunta – a @Transactional não terá efeito se usada para anotar methods privados. O gerador de proxy irá ignorá-los.

Isto está documentado no capítulo 10.5.6 do Manual da spring :

Visibilidade do método e @Transactional

Ao usar proxies, você deve aplicar a anotação @Transactional somente a methods com visibilidade pública. Se você anotar methods protegidos, privados ou visíveis a pacotes com a anotação @Transactional , nenhum erro será gerado, mas o método anotado não exibirá as configurações transacionais configuradas. Considere o uso de AspectJ (veja abaixo) se você precisar anotar methods não públicos.

A pergunta não é privada ou pública, a pergunta é: como ela é invocada e qual implementação AOP você usa!

Se você usar (padrão) Spring Proxy AOP, então todas as funcionalidades AOP fornecidas pelo Spring (como @Transational ) serão consideradas somente se a chamada passar pelo proxy. – Este é normalmente o caso se o método anotado for chamado a partir de outro bean.

Isso tem duas implicações:

  • Como os methods privados não devem ser chamados de outro bean (a exceção é reflexo), sua Anotação @Transactional não é levada em conta.
  • Se o método for público, mas for invocado a partir do mesmo bean, ele não será levado em consideração (esta instrução é correta apenas se (padrão) for utilizado o Spring Proxy AOP).

@ See Spring Reference: Chapter 9.6 9.6 Mecanismos de proxies

IMHO você deve usar o modo aspectJ, em vez dos Spring Proxies, que irão superar o problema. E os Aspectos Transacionais AspectJ são tecidos até mesmo em methods privados (verificados no Spring 3.0).

Por padrão, o atributo @Transactional funciona somente ao chamar um método anotado em uma referência obtida de applicationContext.

 public class Bean { public void doStuff() { doTransactionStuff(); } @Transactional public void doTransactionStuff() { } } 

Isso abrirá uma transação:

 Bean bean = (Bean)appContext.getBean("bean"); bean.doTransactionStuff(); 

Isto não irá:

 Bean bean = (Bean)appContext.getBean("bean"); bean.doStuff(); 

Referência de spring: Usando o @Transactional

Nota: No modo de proxy (que é o padrão), somente chamadas de método ‘externas’ que entram através do proxy serão interceptadas. Isso significa que ‘auto-invocação’, ou seja, um método dentro do object de destino que chama algum outro método do object de destino, não levará a uma transação real em tempo de execução, mesmo se o método invocado estiver marcado com @Transactional !

Considere o uso do modo AspectJ (veja abaixo) se você espera que as auto-invocações sejam envolvidas com transactions também. Neste caso, não haverá um proxy em primeiro lugar; em vez disso, a class de destino será ‘tecida’ (ou seja, seu código de byte será modificado) para transformar @Transactional em comportamento de tempo de execução em qualquer tipo de método.

Sim, é possível usar @Transactional em methods privados, mas, como outros já mencionaram, isso não funcionará imediatamente. Você precisa usar AspectJ. Demorei algum tempo para descobrir como fazê-lo funcionar. Eu vou compartilhar meus resultados.

Eu escolhi usar tecelagem em tempo de compilation em vez de tecelagem em tempo de carregamento porque acho que é uma opção melhor em geral. Além disso, estou usando o Java 8, portanto, talvez seja necessário ajustar alguns parâmetros.

Primeiro, adicione a dependência para aspectjrt.

  org.aspectj aspectjrt 1.8.8  

Em seguida, adicione o plugin AspectJ para fazer o tecimento de bytecode real no Maven (isso pode não ser um exemplo mínimo).

  org.codehaus.mojo aspectj-maven-plugin 1.8  1.8 1.8 1.8   org.springframework spring-aspects       compile     

Por fim, adicione isso à sua class de configuração

 @EnableTransactionManagement(mode = AdviceMode.ASPECTJ) 

Agora você deve poder usar @Transactional em methods privados.

Uma ressalva para esta abordagem: Você precisará configurar o seu IDE para estar ciente de AspectJ caso contrário, se você executar o aplicativo via Eclipse, por exemplo, pode não funcionar. Certifique-se de testar contra uma configuração direta do Maven como uma verificação de integridade.

Por favor veja este documento:

No modo proxy (que é o padrão), somente as chamadas de método externo que chegam pelo proxy são interceptadas. Isso significa que a auto-chamada, na verdade, um método dentro do object de destino que chama outro método do object de destino, não levará a uma transação real em tempo de execução, mesmo se o método chamado estiver marcado com @Transactional.

Considere o uso do modo AspectJ (consulte o atributo mode na tabela abaixo) se você espera que as auto-chamadas também sejam agrupadas com transactions. Neste caso, não haverá um proxy em primeiro lugar; em vez disso, a class de destino será modificada (isto é, seu código de byte será modificado) para transformar @Transactional em comportamento de tempo de execução em qualquer tipo de método.

—————————-sobre

então, anher maneira é usuário BeanSelfAware

A resposta é não. Por favor, veja Spring Reference: Usando @Transactional :

A anotação @Transactional pode ser colocada antes de uma definição de interface, um método em uma interface, uma definição de class ou um método público em uma class

Intereting Posts