Tem como controlar transações entre serviços via Vraptor?

8 respostas
bland

Olá pessoal,

Eu tenho o Vraptor em meus serviços e surgiu essa dúvida do assunto do tópico.

Eu tenho um serviço criado que é responsável por fazer uma “orquestração”, só que este mesmo serviço deve, também, garantir a transação, ou seja, se algo der errado no segundo serviço, o primeiro deve dar rollback.

Se alguém puder me ajudar, ficarei grato.

De antemão, obrigado pela ajuda.

8 Respostas

Lucas_Cavalcanti

Ter tem sim… O que você quer se chama transação distribuída, e é uma coisa bastante complexa de ser feita.

Já tem coisa pronta, tipo o Spring Transaction, ou algum recurso de servidor de aplicações, é só usar isso a partir do VRaptor.

bland

Olá Lucas, obrigado pela sua resposta.

Então, eu tentei usar o @Transaction do Spring, porém não tive sucesso.

Por exemplo, tenho um método assim (dentro de um Controller):

@Consumer
@Post
@Path( "/integrator" )
@Transaction
public void integrate( ... ) {
}

E dentro desse método eu faço a chamada para os dois outros serviços.

Contudo, quando eu tenho o @Transaction nesse método, ele não é executado. Dá logo um erro na execução.

Se tem como fazer, como poderia ser? Tem algum exemplo?

Vale lembrar que dentro de cada método dos meus outros dois serviços eu tenho eles assinados como sendo transacionais.

Obrigado, de antemão.

Lucas_Cavalcanti

qual erro?

bland

Infelizmente não tenho ele agora, o problema está no trabalho.

Na segunda te passarei o erro.

bland

Olá Lucas, tudo bem?

Refiz os testes aqui e segue o erro:

Aqui vai a minha classe (o meu Controller):

@Resource
public class LancaExameController {
	
	Logger logger = Logger.getLogger( getClass() );
	
	private Result result;
	
	public LancaExameController( Result result ) {
		
		logger.info( "Instanciando o controlador de lançamento de exames na conta do paciente." );
		
		this.result = result;
	}

	@Post
	@Consumes
	@Path( "/lancamentoExames" )
	@Transactional
	public void lancamentoExames( SolicitacaoExameDto solicitacaoExameDto ) {
		
		logger.info( "Iniciando o método 'lancamentoExames'." );
		
		try {

			// Chamada do primeiro serviço

			// Chamada do segundo serviço
			
			result.use( Results.status() ).ok();
			
		} catch ( Exception ex ) {
			
			logger.error( "Erro ao registrar os itens a partir de uma solicitacaoExameDto.", ex.getCause() );

			result.use( Results.status() ).header( "errorMessage", ex.getMessage() );
			result.use( Results.status() ).badRequest( ex.getMessage() );
		}
	}

Pela mensagem de erro eu acredito que eu não consigo usar o @Transactional fora do escopo do Spring, ou seja, dentro de um bean que seja gerenciado por ele.

Se eu retirar a anotação, esse erro não acontece, porém, eu não consigo manter a execução dos serviços dentro de uma transação única.

Estou fazendo algo de errado?

Obrigado mais uma vez.

Lucas_Cavalcanti

se vc usa @Transactional do Spring, as classes não podem ter construtores com argumentos, ou vc tem que sempre referenciar as dependências via interface.

No caso dos Controllers, o único jeito é tirando o construtor. Nos outros componentes vc pode criar uma interface e continuar a usar os construtores.

jeito fácil. Troque:

public LancaExameController( Result result ) {  
          
        logger.info( "Instanciando o controlador de lançamento de exames na conta do paciente." );  
          
        this.result = result;  
    }

por:

@Autowired // ou @Inject
public void init( Result result ) {  
          
        logger.info( "Instanciando o controlador de lançamento de exames na conta do paciente." );  
          
        this.result = result;  
    }
bland

Lucas,

Fiz o que você sugeriu e funcionou. Consigo utilizar o @Transactional. Contudo, ele não garante a transação remotamente.

Eu não entendi muito bem quando sugeriu utilizar Interfaces para os outros componentes. Esses seriam os componentes do Spring ou do Vraptor (Controllers)?

E por mais que eu replique isso (a maneira que você sugeriu para adotar a transação do Spring) para os outros controladores, como repassar a transação para os outros controladores?

Andei pesquisando isso, mas não tive muito sucesso.

Obrigado pela ajuda.

Lucas_Cavalcanti

seriam componentes tanto do Spring qto do VRaptor… a idéia é ter sempre uma interface para o componente, e ao invés das outras classes referenciarem a implementação, referenciar a interface (nas dependencias).

Por padrão o Spring não vai garantir transações remotas mesmo, vc vai ter que configurar coisas a mais. Não conheço de cabeça como fazer isso, precisa pesquisar mesmo…

tenta algo como spring distributed transactions, two phase commit, coisas do tipo

Criado 9 de dezembro de 2011
Ultima resposta 12 de dez. de 2011
Respostas 8
Participantes 2