java “本地事务已经有 1 个非 XA 资源:无法添加更多资源”错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2878597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:15:46  来源:igfitidea点击:

"Local transaction already has 1 non-XA Resource: cannot add more resources" error

javahibernatejdbcejb

提问by jthg

After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources. But:

在阅读了有关此错误的先前问题后,似乎所有人都得出结论,您需要在所有数据源上启用 XA。但:

  1. What if I don't want a distributed transaction? What would I do if I want to start transactions on two different databases at the same time, but commit the transaction on one database and roll back the transaction on the other?
  2. I'm wondering how my code actually initiated a distributed transaction. It looks to me like I'm starting completely separate transactions on each of the databases.
  1. 如果我不想要分布式事务怎么办?如果我想同时在两个不同的数据库上启动事务,但在一个数据库上提交事务并在另一个数据库上回滚事务,我该怎么办?
  2. 我想知道我的代码实际上是如何启动分布式事务的。在我看来,我正在每个数据库上启动完全独立的事务。

Info about the application:

关于应用程序的信息:

The application is an EJB running on a Sun Java Application Server 9.1

该应用程序是在 Sun Java Application Server 9.1 上运行的 EJB

I use something like the following spring context to set up the hibernate session factories:

我使用类似以下 spring 上下文来设置休眠会话工厂:

<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>

Both of the JNDI resources are javax.sql.ConnectionPoolDatasoure's. They actually both point to the same connection pool, but we have two different JNDI resources because there's the possibility that the two, completely separate, groups of tables will move to different databases in the future.

这两个 JNDI 资源都是 javax.sql.ConnectionPoolDatasoure 的。它们实际上都指向同一个连接池,但是我们有两个不同的 JNDI 资源,因为这两个完全独立的表组将来可能会移动到不同的数据库。

Then in code, I do:

然后在代码中,我这样做:

sessionA = dbASessionFactory.openSession();
sessionB = dbBSessionFactory.openSession();
sessionA.beginTransaction();
sessionB.beginTransaction();

The sessionB.beginTransaction() line produces the error in the title of this post - sometimes. I ran the app on two different sun application servers. On one runs it fine, the other throws the error. I don't see any difference in how the two servers are configured although they do connect to different, but equivalent databases.

sessionB.beginTransaction() 行会在这篇文章的标题中产生错误 - 有时。我在两个不同的 Sun 应用程序服务器上运行该应用程序。一个运行正常,另一个抛出错误。尽管这两个服务器确实连接到不同但等效的数据库,但我看不出它们的配置方式有什么不同。

So the question is

所以问题是

  1. Why doesn't the above code start completely independent transactions?
  2. How can I force it to start independent transactions rather than a distributed transaction?
  3. What configuration could cause the difference in behavior between the two application servers?
  1. 为什么上面的代码不启动完全独立的事务?
  2. 如何强制它启动独立事务而不是分布式事务?
  3. 什么配置会导致两个应用程序服务器之间的行为差​​异?

Thanks.

谢谢。

P.S. the stack trace is:

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 ...]

回答by ewernli

1 Why doesn't the above code start completely independent transactions?

1 为什么上面的代码不启动完全独立的事务?

The app. server manages the transaction for you which can, if necessary, be a distributed transaction. It enlists all the participants automatically. When there's only one participant, you don't notice any difference with a plain JDBC transaction, but if there are more than one, a distributed transaction is really needed, hence the error.

应用程序。服务器为您管理事务,如有必要,它可以是分布式事务。它会自动招募所有参与者。当只有一个参与者时,您不会注意到与普通 JDBC 事务有任何区别,但如果有多个参与者,则确实需要分布式事务,因此会出现错误。

2 How can I force it to start independent transactions rather than a distributed transaction?

2 如何强制它启动独立事务而不是分布式事务?

You can configure the datasource to be XA or Local. The transactional behavior of Spring/Hibernate can also be configured to use either regular JDBC transactions or delegate the management of transactions to the JTA distributed transaction manager.

您可以将数据源配置为 XA 或 Local。Spring/Hibernate 的事务行为也可以配置为使用常规 JDBC 事务或将事务的管理委托给 JTA 分布式事务管理器。

I suggest you switch the datasource to non-XA and try to configure Spring/Hibernate to use the JDBC transactions. You should find the relevant information in the documentation, here what I suspect is the line to change:

我建议您将数据源切换到非 XA 并尝试配置 Spring/Hibernate 以使用 JDBC 事务。您应该在文档中找到相关信息,这里我怀疑是要更改的行:

<bean id="txManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />

This should essentially means that you are not using the app. server distributed transaction manager.

这基本上意味着您没有使用该应用程序。服务器分布式事务管理器。

3 What configuration could cause the difference in behavior between the two application servers?

3 什么配置会导致两个应用程序服务器之间的行为差​​异?

If you have really exactly the same app and configuration, this means that in one case only one participant is enlisted in the dist. transaction, while there are two in the 2nd case. One participant corresponds to one physical connection to a database usually. Could it be that in one case, you use two schema on two different databases, while in the 2nd case you use two schemaon the samephysical database? A more probable explanation would be that the datasource were configured differently on the two app. server.

如果您的应用程序和配置确实完全相同,这意味着在一种情况下,dist 中只有一名参与者。交易,而在第二种情况下有两个。一个参与者通常对应一个到数据库的物理连接。是不是在一种情况下,您在两个不同的数据库上使用了两个模式,而在第二种情况下,您在同一个物理数据库上使用了两个模式?更可能的解释是数据源在两个应用程序上的配置不同。服务器。

PS: If you use JTA distributed transactions, you should use UserTransaction.{begin,commit,rollback}rather than their equivalent on the Session.

PS:如果你使用 JTA 分布式事务,你应该UserTransaction.{begin,commit,rollback}Session.

回答by Pascal Thivent

After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources.

在阅读了有关此错误的先前问题后,似乎所有人都得出结论,您需要在所有数据源上启用 XA。

No, not all, all except one (as the exception is saying) if your application server supports Logging Last Resource (LLR) optimization (which allows to enlist one non-XA resource in a global transaction).

不,不是全部,除非您的应用程序服务器支持 Logging Last Resource (LLR) 优化(允许在全局事务中登记一个非 XA 资源),否则所有除外(正如例外所说)。

Why doesn't the above code start completely independent transactions?

为什么上面的代码不启动完全独立的事务?

Because you aren't. When using beginTransaction()behind EJB Session Beans, Hibernate will join the JTA transaction (refer to the documentationfor full details). So the first call just works but the second call means enlisting another transactional resource in the current transaction. And since none of your resources are XA, you get an exception.

因为你不是。当beginTransaction()在 EJB Session Beans 后面使用时,Hibernate 将加入 JTA 事务(有关完整详细信息,请参阅文档)。所以第一个调用正常工作,但第二个调用意味着在当前事务中登记另一个事务资源。由于您的所有资源都不是 XA,因此您会得到一个例外。

How can I force it to start independent transactions rather than a distributed transaction?

如何强制它启动独立事务而不是分布式事务?

See @ewernlianswer.

请参阅@ewernli答案。

What configuration could cause the difference in behavior between the two application servers?

什么配置会导致两个应用程序服务器之间的行为差​​异?

No idea. Maybe one of them is using at least one XA datasource.

不知道。也许其中之一正在使用至少一个 XA 数据源。