8

Estoy tratando de usar 2 unidades de persistencia dentro de la misma transacción en una aplicación Java EE implementada en Glassfish.EJB3 - utilizando 2 unidades de persistencia dentro de una transacción (Excepción: la transacción local ya tiene 1 recurso no XA)

las 2 unidades de persistencia se definen en persistence.xml, como sigue:

<persistence-unit name="BeachWater"> 
<jta-data-source>jdbc/BeachWater</jta-data-source> 
... 
<persistence-unit name="LIMS"> 
<jta-data-source>jdbc/BeachWaterLIMS</jta-data-source> 
... 

Estas unidades de persistencia corresponden a recursos JDBC y grupos de conexión que había definidos en Glassfish como sigue (incluir uno aquí ya que ambos son idénticos, aparte de nombres & información de conexión de base de datos):

JDBC Resource: 
JNDI Name: jdbc/BeachWaterLIMS 
Pool Name: BEACHWATER_LIMS 

Connection Pool: 
Name: BEACHWATER_LIMS 
Datasource Classname: com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource 
Resource Type: javax.sql.ConnectionPoolDataSource 

Hay 3 beans de sesión sin estado, LimsServiceBean, AnalysisServiceBean y AnalysisDataTransformationServiceBean.

Éstos son los fragmentos relevantes de LimsServiceBean:

@PersistenceContext(unitName = "LIMS") 
EntityManager em; 
... 
public ArrayList<Sample> getLatestLIMSData() { 
    Query q = em.createNamedQuery("Sample.findBySubTypeStatus"); 
    return new ArrayList<Sample>(q.getResultList()); 
} 

De AnalysisServiceBean:

@PersistenceContext(unitName = "BeachWater") 
EntityManager em; 
... 
public ArrayList<AnalysisType> getAllAnalysisTypes() { 
    Query q = em.createNamedQuery("AnalysisType.findAll"); 
    return new ArrayList<AnalysisType>(q.getResultList()); 
} 

Y desde AnalysisDataTransformationServiceBean:

@EJB 
private AnalysisService analysisService; 

@EJB 
private LimsService limsService; 

public void transformData() { 
    List<AnalysisType> analysisTypes = analysisService.getAllAnalysisTypes(); 
    ArrayList<Sample> samples = limsService.getLatestLIMSData(); 

Este llamado a limsService.getLatestLIMSData() provocó la siguiente excepción:

 [exec] Caused by: javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean; nested exception is: Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.1 (Build b60e-fcs (12/23/2008))): oracle.toplink.essentials.exceptions.DatabaseException 
[exec] Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: java.lang.IllegalStateException: Local transaction already has 1 non-XA Resource: cannot add more resources. 

La consulta de esta página, http://msdn.microsoft.com/en-us/library/ms378484.aspx (entre muchos otros), he intentado cambiar la definición de las agrupaciones de conexiones a:

Connection Pool: 
Name: BEACHWATER_LIMS 
Datasource Classname: com.microsoft.sqlserver.jdbc.SQLServerXADataSource 
Resource Type: javax.sql.XADataSource 

Ping a través de la consola de administración de GlassFish tiene éxito, pero llaman a analysisService. getAllAnalysisTypes() ahora arroja una excepción:

Caused by: javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean; nested exception is: Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.1 (Build b60e-fcs (12/23/2008))): oracle.toplink.essentials.exceptions.DatabaseException 
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: javax.transaction.SystemException 

The resource manager is doing work outside a global transaction javax.transaction.xa.XAException: com.microsoft.sqlserver.jdbc.SQLServerException: Failed to create the XA control connection. Error: "Could not find stored procedure 'master..xp_sqljdbc_xa_init_ex'." 

¿Alguna idea?

+0

Posible duplicado de [¿Cómo evitar "la transacción local ya tiene 1 excepción de recurso no XA"] (https://stackoverflow.com/questions/2687121/how-to-prevent-local-transaction-already-has -1-non-xa-resource-exception) –

Respuesta

6

Cambio de configuración de agrupación de conexiones en Glassfish:

Connection Pool: 
Name: BEACHWATER_LIMS 
Datasource Classname: com.microsoft.sqlserver.jdbc.SQLServerXADataSource 
Resource Type: javax.sql.XADataSource 

siga los pasos en el blog de Senthil Balakrishnan, "¿Cómo hacer MSSQL servidor de origen de datos XA trabajo?" aquí, http://www.senthilb.com/2010/01/how-to-make-xa-datasource-work-in-mssql.html.

Restart Glassfish.

+0

Gracias por los comentarios. –

4

Para utilizar dos unidades de persistencia (y por lo tanto dos fuentes de datos) dentro de una transacción, necesita usar conexiones XA y configurar sus pools en consecuencia (al menos uno de ellos, GlassFish admite la última optimización del agente que permite aliste un recurso que no sea XA, vea http://docs.sun.com/app/docs/doc/820-7695/beanm?a=view). Eso fue por el primer error.

Para el segundo error, parece difícil decir algo con el nivel actual de detalles. ¿Podría proporcionar el seguimiento de la pila (activar el registro más fino si es necesario)?

+0

Gracias Pascal.Desde entonces descubrí más detalles en los registros: El administrador de recursos está trabajando fuera de una transacción global javax.transaction.xa.XAException: com.microsoft.sqlserver.jdbc.SQLServerException: Error al crear la conexión de control XA. Error: "No se pudo encontrar el procedimiento almacenado 'master..xp_sqljdbc_xa_init_ex'." He encontrado una solución sugerida aquí, http://www.senthilb.com/2010/01/how-to-make-xa-datasource-work-in-mssql.html y he solicitado los cambios pertinentes en el servidor. Se actualizará aquí cuando vuelva a probar. – Sorcha

+0

@Sorcha Gracias por los comentarios. No dude en dejar un comentario después de la actualización para que me notifiquen. ¡Pero tengo la sensación de que estás en el camino correcto! –

+0

Ver respuesta agregada. Funciona perfectamente ahora Gracias de nuevo por tu contribución. – Sorcha

Cuestiones relacionadas