阅读有关此错误的先前问题之后,似乎所有这些人都得出结论,您需要在所有数据源上启用XA。但:
有关该应用程序的信息:
该应用程序是在Sun Java Application Server 9.1上运行的EJB。
我使用类似以下spring上下文的内容来设置hibernate会话工厂:
<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>
这两个JNDI资源都是javax.sql.ConnectionPoolDatasoure的。它们实际上都指向同一个连接池,但是我们有两个不同的JNDI资源,因为将来,这两个完全独立的表组可能会移动到不同的数据库。
然后在代码中,我这样做:
sessionA = dbASessionFactory.openSession(); sessionB = dbBSessionFactory.openSession(); sessionA.beginTransaction(); sessionB.beginTransaction();
sessionB.beginTransaction()行在此帖子的标题中产生错误- 有时。我在两个不同的sun应用程序服务器上运行了该应用程序。一次运行正常,另一次则抛出错误。尽管这两个服务器确实连接到不同但等效的数据库,但在配置方式上没有任何区别。
所以问题是
谢谢。
PS堆栈跟踪为:
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上面的代码为什么不开始完全独立的事务?
该应用程序。服务器为您管理交易,如果需要,交易可以是分布式交易。它会自动招募所有参与者。当只有一个参与者时,您不会注意到与普通JDBC事务有什么区别,但是如果有多个参与者,则确实需要分布式事务,因此会出现错误。
2如何强制它开始独立事务而不是分布式事务?
您可以将数据源配置为XA或Local。还可以将Spring / Hibernate的事务行为配置为使用常规JDBC事务,或将事务管理委托给JTA分布式事务管理器。
我建议您将数据源切换到非XA并尝试将Spring / Hibernate配置为使用JDBC事务。您应该在文档中找到相关信息,这里我怀疑是要更改的行:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />
从本质上讲,这应该意味着您没有在使用该应用程序。服务器分布式事务管理器。
3哪种配置可能导致两个应用程序服务器之间的行为不同?
如果您确实拥有完全相同的应用程序和配置,则意味着在一种情况下,dist中仅招募一名参与者。交易,而第二种情况有两个。一个参与者通常对应一个与数据库的物理连接。可能是在一种情况下,您在两个不同的数据库上使用了两个架构,而在第二种情况下,您在 同一个 物理数据库上使用了两个 架构 吗?一个更可能的解释是,两个应用程序上的数据源配置不同。服务器。 __
PS:如果您使用JTA分布式事务,则应在上使用UserTransaction.{begin,commit,rollback}而不是等效的方法Session。
UserTransaction.{begin,commit,rollback}
Session