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

slmsl1lt  于 2023-06-04  发布在  Java
关注(0)|答案(1)|浏览(139)

我使用Spring Integration XML配置来轮询一些数据库表,然后进行一些处理。一切都很好,直到我们引入了多个数据源。之后,我们得到间歇性NoUniqueBeanDefinitionException异常。
问题是我们不知道这个异常来自哪个poller(我们使用的是基于xml的配置),因为我们有很多轮询器。由于堆栈跟踪显示了AbstractPollingEndpoint.java,因此我们查看了所有轮询器并验证了transaction-manager是否正确设置。
代码:

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

有没有办法从下面的堆栈中找出位于AbstractPollingEndpoint$Poller$1.run开头的轮询器的id,以便我们进一步调试?
或者我们的多数据源配置中缺少的任何其他内容。

nxowjjhe

nxowjjhe1#

在stacktrace中可以看到:

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

所以问题是spring找到了两个符合自动装配条件的bean。尝试使用@Shailesh建议的属性将其中一个bean设置为primary:

<bean primary="true|false"/>

或者使用限定符将两个事务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>

当你想使用一个特定的事务管理器时,使用如下注解指定它:

@Transactional("transactionManagerOne")

注意:您也可以通过xml来配置
您可以使用@Transactional annotation的value属性来可选地指定要使用的PlatformTransactionManager的标识。这可以是bean名称,也可以是事务管理器bean的限定符值。如果找不到专门限定的PlatformTransactionManager bean,则仍使用默认的目标bean名称transactionManager。
正式文件

相关问题