简体   繁体   English

在 Spring 集成中使用多个事务管理器时出现 NoUniqueBeanDefinitionException

[英]NoUniqueBeanDefinitionException when using multiple transaction managers in Spring Integration

Am using Spring Integration XML configuration for polling some database tables and then doing some processing.我正在使用 Spring 集成 XML 配置来轮询一些数据库表,然后进行一些处理。 Everything was working fine, until we introduced multiple data sources.一切正常,直到我们引入了多个数据源。 After that we are getting intermittent NoUniqueBeanDefinitionException exceptions.之后,我们会收到间歇性NoUniqueBeanDefinitionException异常。

Problem is we dont know from which poller is this exception coming (we are using xml based configuration), since we have a lot of pollers.问题是我们不知道这个异常来自哪个poller (我们使用的是基于 xml 的配置),因为我们有很多轮询器。 Since the stack trace shows the AbstractPollingEndpoint.java , we looked at all the pollers and verified that the transaction-manager is set properly.由于堆栈跟踪显示AbstractPollingEndpoint.java ,我们查看了所有轮询器并验证transaction-manager设置正确。

Code:代码:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
        <property name="dataSource" ref="dataSource" />
</bean>

<bean id="transactionManagerSec" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactorySecondary"/>
        <property name="dataSource" ref="dataSourceSec" />
</bean>

<jpa:repositories base-package="com.acme.dao" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" />
<jpa:repositories base-package="com.acme.tmpdao" entity-manager-factory-ref="entityManagerFactorySecondary" transaction-manager-ref="transactionManagerSec" />

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" primary="true" id="entityManagerFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="persistenceUnitName" value="${spring.persistence.unitname}" />
        <property name="persistenceProvider" ref="eclipsePP" />
</bean>

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" primary="false" id="entityManagerFactorySecondary">
        <property name="dataSource" ref="dataSourceSec"/>
        <property name="persistenceUnitName" value="${spring.secondary.persistence.unitname}" />
        <property name="persistenceProvider" ref="eclipsePPSec" />
</bean>

<bean class="org.eclipse.persistence.jpa.PersistenceProvider" id="eclipsePP" />
<bean class="org.eclipse.persistence.jpa.PersistenceProvider" id="eclipsePPSec" />

<int:transaction-synchronization-factory id="txSyncFactory">
        <int:before-commit channel="updateEntityChannel" />
</int:transaction-synchronization-factory>

<int-jpa:inbound-channel-adapter id="procStateAdapter"  channel="inProcStateChannel"
                    entity-manager="entityManagerFactory"
                    auto-startup="true"
                    jpa-query="select <SqlQuery> order by en.lastUpdatedTime"
                    max-results="10"
                    >
        <int:poller max-messages-per-poll="10" fixed-rate="10" >
            <int:transactional propagation="REQUIRES_NEW" transaction-manager="transactionManager" synchronization-factory="txSyncFactory"/>
        </int:poller>
    </int-jpa:inbound-channel-adapter>
2019-10-13 07:51:16,625 [task-scheduler-5] ERROR o.s.i.h.LoggingHandler:handleMessageInternal:192 - org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: transactionManager,transactionManagerSec
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:368)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:366)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy409.toString(Unknown Source)
        at java.lang.String.valueOf(String.java:2994)
        at java.lang.StringBuilder.append(StringBuilder.java:131)
        at org.springframework.integration.endpoint.PollingConsumer.handleMessage(PollingConsumer.java:141)
        at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:272)
        at org.springframework.integration.endpoint.AbstractPollingEndpoint.access$000(AbstractPollingEndpoint.java:58)
        at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:190)
        at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:186)
        at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:353)
        at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
        at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51)
        at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344)
        at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
        at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

Is there any way to find out the id of the poller that is at the beginning of the AbstractPollingEndpoint$Poller$1.run from the stack below so we can debug this further?有没有办法从下面的堆栈中找出位于AbstractPollingEndpoint$Poller$1.run开头的轮询器的id ,以便我们进一步调试?

Or anything else that is missing from our config for multiple data source.或者我们的多数据源配置中缺少的任何其他内容。

In your stacktrace it can be seen that:在您的堆栈跟踪中可以看出:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected 
single matching bean but found 2: transactionManager,transactionManagerSec

So the issue is that spring finds two qualifying beans for autowiring.所以问题是 spring 找到两个符合条件的 bean 进行自动装配。 Try setting one of your bean as primary using the attribute as @Shailesh suggested:尝试使用@Shailesh建议的属性将您的一个bean设置为主要:

<bean primary="true|false"/>

or use a qualifier to set the two transaction beans apart and then specify which transaction manager to be used in code like:或使用限定符将两个事务 bean 分开,然后指定要在代码中使用的事务管理器,例如:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
        <property name="dataSource" ref="dataSource" />
        <qualifier value="transactionManagerOne"/>
</bean>

<bean id="transactionManagerSec" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactorySecondary"/>
        <property name="dataSource" ref="dataSourceSec" />
        <qualifier value="transactionManagerSecond"/>
</bean>

and when you want to use a particular transaction manager specify it using the annotation like:当您想使用特定的事务管理器时,请使用以下注释指定它:

@Transactional("transactionManagerOne")

Note: You could configure this via xml as well注意:您也可以通过 xml 进行配置

You can use the value attribute of the @Transactional annotation to optionally specify the identity of the PlatformTransactionManager to be used.您可以使用 @Transactional 注释的 value 属性来选择性地指定要使用的 PlatformTransactionManager 的身份。 This can either be the bean name or the qualifier value of the transaction manager bean.The default target bean name, transactionManager, is still used if no specifically qualified PlatformTransactionManager bean is found.这可以是 bean 名称或事务管理器 bean 的限定符值。如果没有找到特别限定的 PlatformTransactionManager bean,则仍使用默认目标 bean 名称 transactionManager。

Official Doc官方文件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM