Como ter controle sobre a transação - Seam/JTA

2 respostas
S

Pessoal, utilizo o Seam e todas as transações são gerenciados pelo container (JTA), mas surgiu um caso de uso em que preciso ter maior controle sobre as transações, pois preciso dar um commit() para que seja atualizado no banco antes de finalizar o método. Já tentei usar o getTransaction(), mas gera uma excessão dizendo não ser possível, justamente por causa do JTA.

Tentei transformar o classe em um Bean gerenciavel utilizando a anotação @TransactionManagement(TransactionManagementType.BEAN) mas também não deu certo.

O fato é que preciso dar dois commit’s e só o primeiro funciona, não estou conseguindo entender porque, não sei se o problema é gerado pelo primeiro commit e aí acontece alguma coisa com o entityManager e ele
não persiste.

Se alguém tiver paciência de olhar meu código está logo abaixo.
Tentei explicar bem o problema, se alguém puder ajudar agradeço.

Abraços!!

@Name("readingDevicesAction")
@Scope(ScopeType.CONVERSATION)
@TransactionManagement(TransactionManagementType.BEAN)
public class ReadingDevicesAction implements Serializable {	
	
	@In 
	EntityManager entityManager;
	private MeasureInterFace measureInterFace;
	
	@End
	public String saveCommand()  {			
		boolean existDeviceConnected = readingDevicesDAO.existDeviceConnectedDAO(measure);
		
		if(existDeviceConnected == true) {	
			Register registerComplementary = commomMethodsDAO.findRegisterByComplementDAO(complement);	
			// valores da interFaceWrite vem da View (xhtml)
			this.saveInterFace(interFaceWrite, registerComplementary);			
			
			this.verifyExecution(interFaceWrite);			
			
			if(measureInterFace == null) {
				// se entrar aqui NÂO remove, porque o entityManager não "funciona" depois que dou commit
				entityManager.remove(interFaceWrite);
				entityManager.createNativeQuery("unlock tables interface");		
				FacesMessages.instance().add("O Comando de escrita não pôde ser inserido!!");
				return null;			
			} else {				
				interFaceRead = new InterFace();
				this.saveInterFace(interFaceRead, measure.getRegister());				
				this.verifyExecution(interFaceRead);
				
				if(measureInterFace == null) {
					FacesMessages.instance().add("Comando de escrita inserido com sucesso, " +
						"mas a leitura não pôde ser atualizada!");
				} else {
					FacesMessages.instance().add("Comando inserido com sucesso!");
				}
			}
			return "saveCommand";
		} else {
			FacesMessages.instance().add("Dispositivo desconectado, portanto, o Comando não pôde ser inserido!!");
			return null;
		}	
	}
	
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void saveInterFace(InterFace i, Register r) {
		/**
		 * na primeira vez que entra no método, NÃO inicia a transação, o tx.begin() gera uma exception, 
		 * acaba pegando a transação ativa do JTA, mas o valor é inserido corretamente no banco
		 *
		 * na segunda vem que entra no método, é iniciada uma nova transação, porém, passa pelo 
		 * em.persist(i) sem "funcionar". Não é gerado o insert no log do console, muito menos quando dá o tx.commit()
		 */
		UserTransaction tx = Transaction.instance();	
		tx.begin();	
		i.setDate(new Date());
		i.setExecute(0);
		i.setQuantity(1);
		i.setType((byte) 0);
		i.setRegister(r);
		i.setInputValue(inputValue);
		em.persist(i);
		tx.commit();
	}
	
	// método que verifica se o Socket conseguiu executar o Comando, ou seja, inserir valor no banco
	public void verifyExecution(InterFace i) {				
		int timer = 0;		
		while(timer < 10) {
			try {
				Thread.sleep(3000);
				measureInterFace = readingDevicesDAO.existInterfaceExecutedDAO(i);									
				if(measureInterFace != null) {						
					break;
				} 								
				timer++;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}	
	}
}

2 Respostas

L

Eu teria uma sugestão rápida e “suja” de resolver o problema. Não sei se te atenderia, mas tem boas chances de funcionar.
Se tua aplicação não precisa trabalhar com transações distribuidas (JTA) e “two fases commit”, então, primeiramente, desabilite o JTA modificando no persistence.xml o atributo para “RESOURCE_LOCAL” e o datasource para “non-jta-datasource”.
Isso de imediato te dará controle total sobre as transações e voce poderá iniciar, confirmar e desfazer as transações como desejar e de forma manual.

S

Luiz, nesse ponto do projeto não posso mudar mais.
Mas valeu pela ajuda. :slight_smile:

Criado 10 de setembro de 2010
Ultima resposta 10 de set. de 2010
Respostas 2
Participantes 2