java - manejo - "La transacción local ya tiene 1 recurso no XA: no se pueden agregar más recursos" error
manejo de gridlayout en java (2)
Después de leer las preguntas anteriores sobre este error, parece que todos concluyen que debe habilitar XA en todas las fuentes de datos. Pero:
- ¿Qué pasa si no quiero una transacción distribuida? ¿Qué haría si quisiera iniciar transacciones en dos bases de datos diferentes al mismo tiempo, pero comprometer la transacción en una base de datos y deshacer la transacción en la otra?
- Me pregunto cómo mi código realmente inició una transacción distribuida. Me parece que estoy comenzando transacciones completamente separadas en cada una de las bases de datos.
Información sobre la aplicación:
La aplicación es un EJB ejecutándose en Sun Java Application Server 9.1
Utilizo algo como el siguiente contexto de primavera para configurar las fábricas de sesión de hibernación:
<bean id="dbADatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbA"/>
</bean>
<bean id="dbASessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbADatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaA
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
<bean id="dbBDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbB"/>
</bean>
<bean id="dbBSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbBDatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaB
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
Ambos recursos JNDI son javax.sql.ConnectionPoolDatasoure. De hecho, ambos apuntan al mismo grupo de conexiones, pero tenemos dos recursos JNDI diferentes porque existe la posibilidad de que los dos grupos de tablas completamente separados se muevan a bases de datos diferentes en el futuro.
Luego en el código, hago:
sessionA = dbASessionFactory.openSession();
sessionB = dbBSessionFactory.openSession();
sessionA.beginTransaction();
sessionB.beginTransaction();
La línea sessionB.beginTransaction () produce el error en el título de esta publicación, a veces. Ejecuté la aplicación en dos servidores de aplicaciones solares diferentes. En uno corre bien, el otro arroja el error. No veo ninguna diferencia en cómo se configuran los dos servidores, aunque se conectan a bases de datos diferentes, pero equivalentes.
Entonces la pregunta es
- ¿Por qué el código anterior no inicia transacciones completamente independientes?
- ¿Cómo puedo obligarlo a iniciar transacciones independientes en lugar de una transacción distribuida?
- ¿Qué configuración podría causar la diferencia de comportamiento entre los dos servidores de aplicaciones?
Gracias.
PS el rastro de la pila es:
Local transaction already has 1 non-XA Resource: cannot add more resources.
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:124)
at com.sun.enterprise.resource.ResourceManagerImpl.registerResource(ResourceManagerImpl.java:144)
at com.sun.enterprise.resource.ResourceManagerImpl.enlistResource(ResourceManagerImpl.java:102)
at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
at [application code ...]
1 ¿Por qué el código anterior no inicia transacciones completamente independientes?
La aplicación. el servidor gestiona la transacción para usted, que puede, si es necesario, ser una transacción distribuida. Enlista a todos los participantes automáticamente. Cuando solo hay un participante, no observa ninguna diferencia con una transacción JDBC simple, pero si hay más de uno, realmente se necesita una transacción distribuida, de ahí el error.
2 ¿Cómo puedo obligarlo a iniciar transacciones independientes en lugar de una transacción distribuida?
Puede configurar el origen de datos para que sea XA o Local . El comportamiento transaccional de Spring / Hibernate también se puede configurar para usar transacciones JDBC regulares o delegar la administración de transacciones al administrador de transacciones distribuidas de JTA.
Sugiero que cambie la fuente de datos a no XA e intente configurar Spring / Hibernate para usar las transacciones JDBC. Debería encontrar la información relevante en la documentación , aquí lo que sospecho es la línea a cambiar:
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />
Esto debería significar esencialmente que no estás usando la aplicación. servidor administrador de transacciones distribuidas.
3 ¿Qué configuración podría causar la diferencia de comportamiento entre los dos servidores de aplicaciones?
Si tiene exactamente la misma aplicación y configuración, esto significa que en un caso solo se inscribe un participante en el dist. transacción, mientras que hay dos en el segundo caso. Un participante corresponde a una conexión física a una base de datos por lo general. ¿Podría ser que en un caso, use dos esquemas en dos bases de datos diferentes, mientras que en el segundo caso use dos esquemas en la misma base de datos física? Una explicación más probable sería que el origen de datos se configuró de manera diferente en las dos aplicaciones. servidor.
PD: Si usa transacciones distribuidas de JTA, debe usar UserTransaction.{begin,commit,rollback}
lugar de su equivalente en la Session
.
Después de leer las preguntas anteriores sobre este error, parece que todos concluyen que debe habilitar XA en todas las fuentes de datos.
No, no todos, excepto uno (como dice la excepción) si su servidor de aplicaciones admite la optimización del último recurso de registro (LLR) (que permite incluir un recurso que no sea XA en una transacción global).
¿Por qué el código anterior no inicia transacciones completamente independientes?
Porque no lo eres Al usar beginTransaction()
detrás de Session Beans de EJB, Hibernate se unirá a la transacción de JTA (consulte la documentación para obtener detalles completos). Entonces, la primera llamada simplemente funciona, pero la segunda llamada significa alistar otro recurso transaccional en la transacción actual. Y dado que ninguno de sus recursos es XA, obtiene una excepción.
¿Cómo puedo obligarlo a iniciar transacciones independientes en lugar de una transacción distribuida?
Ver @ewernli respuesta.
¿Qué configuración podría causar la diferencia de comportamiento entre los dos servidores de aplicaciones?
Ni idea. Tal vez uno de ellos está utilizando al menos un origen de datos XA.