Problema com transações JPA

Bom dia,
já tentei de várias formas, mas continuo sem ter sucesso nesse problema.
Eu tenho um PhaseListener que uso para abrir uma Transação na fase Restore view e fechá-la na Render Response.

Na abertura da transação ocorre tudo certo…
Executo o que devo executar, o jpa dá os nextval nas tabelas, da os insert nas tabelas daí quando vou fechar a transação dá um erro.

AVISO: JTS5031: Exception [java.lang.RuntimeException: org.postgresql.xa.PGXAException: Erro ao preparar transação] on Resource [prepare] operation.
AVISO: JTS5068: Unexpected error occurred in rollback
org.postgresql.xa.PGXAException: Erro ao cancelar transação preparada
	at org.postgresql.xa.PGXAConnection.rollback(PGXAConnection.java:410)
	at com.sun.gjc.spi.XAResourceImpl.rollback(XAResourceImpl.java:195)
	at com.sun.jts.jta.TransactionState.rollback(TransactionState.java:193)
	at com.sun.jts.jtsxa.OTSResourceImpl.rollback(OTSResourceImpl.java:333)
	at com.sun.jts.CosTransactions.RegisteredResources.distributeRollback(RegisteredResources.java:1038)
	at com.sun.jts.CosTransactions.TopCoordinator.rollback(TopCoordinator.java:2290)
	at com.sun.jts.CosTransactions.CoordinatorTerm.commit(CoordinatorTerm.java:420)
	at com.sun.jts.CosTransactions.TerminatorImpl.commit(TerminatorImpl.java:250)
	at com.sun.jts.CosTransactions.CurrentImpl.commit(CurrentImpl.java:623)
	at com.sun.jts.jta.TransactionManagerImpl.commit(TransactionManagerImpl.java:323)
	at com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate.commitDistributedTransaction(JavaEETransactionManagerJTSDelegate.java:186)
	at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:858)
	at com.sun.enterprise.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:208)
	at br.gov.pi.detran.renavam.phaselistener.LazilyPhaseListener.afterPhase(LazilyPhaseListener.java:24)
	at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:189)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:107)
	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at br.gov.pi.detran.renavam.filtros.SessaoUsuarioFilter.doFilter(SessaoUsuarioFilter.java:95)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at br.gov.pi.detran.renavam.filtros.SessaoUsuarioFilter.doFilter(SessaoUsuarioFilter.java:95)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:662)
Caused by: org.postgresql.util.PSQLException: ERRO: transação preparada com identificador "4871251_BQAAAGrtvA5Kb25ueVdpbGxlci1QQyxzZXJ2ZXIsUDEwMA==_Sm9ubnlXaWxsZXItUEMsc2VydmVyLFAxMDAsAA==" não existe
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:302)
	at org.postgresql.xa.PGXAConnection.rollback(PGXAConnection.java:400)
	... 53 more

Daí não dá o commit na transação e então não salva no banco…

Abaixo o código do PhaseListener

public class LazilyPhaseListener implements PhaseListener{

	private static final long serialVersionUID = 4618254648190955899L;
	private UserTransaction userTransaction;
	
	@Override
	public void afterPhase(PhaseEvent event) {
		if(event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)){
			try {
				if (userTransaction.getStatus() != Status.STATUS_MARKED_ROLLBACK) {
					userTransaction.commit();
				} else {
					userTransaction.rollback();
				}
			} catch (Throwable t) {
				try {
					if (userTransaction != null && 
							userTransaction.getStatus() == Status.STATUS_ACTIVE) {
						userTransaction.rollback();
					}
				} catch (Throwable t1) {
				}
				
			}
		}
		
	}

	@Override
	public void beforePhase(PhaseEvent event) {
		if(event.getPhaseId().equals(PhaseId.RESTORE_VIEW)){
			try {
				InitialContext context = new InitialContext();
				userTransaction = (UserTransaction) context.lookup("UserTransaction");
				if (userTransaction.getStatus() != Status.STATUS_ACTIVE) {
					userTransaction.begin();
				}
			} catch (Throwable t) {
				try {
					if (userTransaction != null && 
							userTransaction.getStatus() == Status.STATUS_ACTIVE) {
						userTransaction.rollback();
					}
				} catch (Throwable t1) {
				}
			}
			
		}
		
	}

	@Override
	public PhaseId getPhaseId() {
		return PhaseId.ANY_PHASE;
	}

}

O banco é postgresql 9.0
Uso o servidor Glassfish 3.1.1
O datasource é um XADataSource.
Alguma ideia?
Agradeço.

Já que você está usando um conteiner JEE-full porque você não usa EJB’s locais ? Se tem uma coisa que eu acho uma mão na roda são as transações controladas pelo conteiner.

Eu uso sim, Ejbs @Local
A ideia desse PhaseListener é usar o OpenSessionInView para carregar os relacionamento LAZY necessários na página.
Com isso eu posso por todos os relacionamento LAZY sem me preocupar com erros de inicialização.

Nos selects mesmo disparando a exceção o resultado é carregado normal, mas no insert dá esse problema.
E detalhe não é em todo insert.
Inserts em que antes são feitas outras consultas no banco e até em outros bancos SQL Server, DB2 por exemplo é que ocorrem essa situação.

No caso atual eu faço 2 consultas em um DB2 (sem usar DataSource, é conexão direta mesmo), e algumas consultas no banco local (Postgres).
Ai tento inserir no Postgres e dá esse problema.

Olá,

Acabei de passar pro uma situação que retornava o mesmo erro. Mas, o cotexto era um pouco diferente.
Minha situação envolvia um BO(EJB), um DAO(EJB) e dois ENTITYMANAGER(Oracle e PostGreSql).

No meu caso, um método no BO chamava 3 métodos que realizavam consultas distintas indo num mesmo DAO. Todas as consultas aconteciam sem problemas mas ao finalizar o método do BO ocorria o erro.

Como sou amador em JAVA, não conseguia explicar tecnicamente o motivo. Mas suspeitava de algumas coisas.
Realizei os seguintes passos:
1 - Executei o BO chamando apenas 1 método por vez do DAO.
     Resultado: Não aconteceu o erro.
2 - Executei o BO chamando apenas os 2 métodos que consultavam no PostGreSql
     Resultado: Não aconteceu o erro.
3 - Executei o BO chamando apenas o método que consultava no Oracle.
     Resultado: Não aconteceu o erro.
4 - Isolei (penso eu) a transação do método que realizava a consulta no Oracle seguindo os seguintes passos:
     a) Injetei o BO nele mesmo.
     b) Anotei o método consultaOracle() com @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW).
     c) Mudei a chamada do método de consultaOracle() para bo.consultaOracle().
     Resultado: Não aconteceu o erro.

Moral da história: Eu suspeitava que estava dando confusão o fato de um mesmo método no BO está realizando chamada que chegavam a dois EntityManager distintos. Por isso eu reduzi (penso eu) o 'tempo de vida' da transação de um dos bancos para que no final do método do BO, houvesse somente as transações de um banco de dados para serem tratadas.

Creio que isso não é uma solução... já que eu posso querer, em alguma situação, comitar dados em bancos distintos. Então deveria funcionar da forma que está.

Lendo, vi algumas recomendações para mudar a versão do drive do postgresql. Isto eu não testei. : )


Espero ter contribuído com a vida de alguém retardando o stress e quem sabe uma gastrite. rs