É comum em processamento em lotes precisarmos tratar conjuntos de dados em transações separadas, com isso os frameworks mais conhecidos trazem o atributo REQUIRED NEW para simplesmente adicionarmos a anotação no método e o escopo da transação do método ser alterada.
Segue abaixo as formas de implementar a abertura de novas transações:
Em EJB
@TransactionAttribute(TransactionAttributeType.REQUIRED) public void metodo(){
Java EE 7
@Transactional(Transactional.TxType.REQUIRES_NEW) public void metodo(){
Em Spring
@Transactional(propagation = Propagation.REQUIRES_NEW) public void metodo(){
Agora como utilizar essa anotação para abrir novas transações dentro de métodos transacionais? Naturalmente iríamos separar as funcionalidades em métodos e adicionar Requires new no método que deveria estar em uma nova transação, como no exemplo abaixo.
public class ClasseX { @TransactionAttribute public void metodo1(List<Objeto> lista) { for(Objecto objeto : lista) { metodo2(objeto); } } @TransactionAttribute(REQUIRES_NEW) private void metodo2(Objeto objeto) { // faz uma ação com o objeto } }
O resultado dessa solução é a execução do metodo1 com sucesso, no entanto novas transações não serão criadas nas chamadas do metodo2 e tudo será considerado em uma única transação, isso ocorre porque o metodo2 não passa pelo proxy do framework(EJB/Spring) por ser uma chamada local, dessa forma apenas o metodo1 passa pelo proxy e os dois métodos utilizam a configuração do metodo1.
A solução para que o metodo2 abra novas transações é a extração dele para uma nova classe para que a chamada do metodo2 não seja mais local e passe no proxy do framework, assim fazendo que a anotação do metodo2 seja considerada, como no exemplo abaixo.
public class ClasseX { @Inject private ClasseY classeY; @TransactionAttribute public void metodo1() { for(Objecto objeto : lista) { classeY.metodo2(objeto); } } } public class ClasseY { @TransactionAttribute(REQUIRES_NEW) public void metodo2(Objeto objeto) { // faz uma ação com o objeto } }
Observação: Os proxys gerados pelos frameworks são dinâmicos e utilizam a API de Reflection da JDK.