2014-09-05 16 views
1

我將我的Spring批處理進程從命令行應用程序遷移到包括spring-batch-admin-manager(版本1.3.0)在內的spring啓動webapp。Spring在多個TransactionManager bean之間進行選擇

我的舊命令行應用程序與兩個JPA數據庫和兩個TransactionManager實例一起工作。我記得這一直是一個配置的地獄,讓這個運行。我希望事情變得更加舒適,從Spring Boot開始,但現在情況似乎更糟糕:

Spring無法爲事務選擇正確的TransactionManager實例。

在應用程序啓動時Spring正在訪問我的一個類來執行@PostConstruct帶註釋的代碼塊,從中應該調用事務方法。

@PostConstruct 
public void init() { 
    eventType = eventTypeBo.findByLabel("Sport"); // <-- Calling transactional method 
    //... 
} 

從這裏引發錯誤。看一看堆棧跟蹤:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
      No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: 
      expected single matching bean but found 2: transactionManager,osm.transactionManager 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:313) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:337) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:252) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) 
    at com.sun.proxy.$Proxy89.findByLabel(Unknown Source) 
    at com.company.model.service.impl.EventTypeBo.findByLabel(EventTypeBo.java:43) 
    at com.company.batch.article.utils.converter.SomeConverter.init(SomeConverter.java:83) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    //... 

你可以從錯誤日誌看我TransactionManager s的名爲「transactionManager的」和「osm.transactionManager」。交易被相應地配置:

<!-- DATABASE 1 --> 
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean> 
<tx:annotation-driven transaction-manager="transactionManager" /> 

<!-- DATABASE 2 --> 
<bean id="osm.transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="osm.entityManagerFactory" /> 
</bean> 
<tx:advice id="txAdvice" transaction-manager="osm.transactionManager"> 
    <tx:attributes> 
     <tx:method name="*" /> 
    </tx:attributes> 
</tx:advice> 
<aop:config> 
    <aop:pointcut id="osmServiceOperation" 
     expression="execution(* com.qompa.osm.service.spec..*Service.*(..))" /> 
    <aop:advisor advice-ref="txAdvice" pointcut-ref="osmServiceOperation" /> 
</aop:config> 

我使用兩種不同的GenericDao implementions訪問數據時PersistenceContext S之間區分:

public class OsmGenericDao<T> implements IGenericDao<T> { 

    @PersistenceContext(unitName = "osm.entityManagerFactory") 
    protected EntityManager em; 
    //... 
} 

public class GenericDao<T> implements IGenericDao<T> { 

    @PersistenceContext(unitName = "entityManagerFactory") 
    protected EntityManager em; 
    //... 
} 

似乎一切都fproperly配置:但是還是失敗了!

編輯:據我可以跟隨春天的TransactionAspectSuppor t試圖通過限定符(determineTransactionManager)確定事務管理器。由於findByLabel的@Transactional註解沒有限定它試圖與DefaultListableBeanFactory「S的getBean方法,其中兩個相同類型的咖啡豆中發現的幫助,無法進行進一步的區分,以確定正確的豆。

必須有一個辦法告訴Spring根據持久化上下文選擇transactionManager的

任何想法

+1

將''和''從''中刪除'transaction-manager =「transactionManager」'。相反,在所有地方都使用'@ Transactional'並指定在哪個事務管理器上使用這些'@ Transactional' bean。 – 2014-09-05 11:29:37

+1

我發現一個醜陋的解決方案,因爲我將我的模塊綁定到特定的TransactionManager名稱。它一直在工作,所以它現在應該... ...一定有另一種方式! – achingfingers 2014-09-05 11:33:10

+0

所以你不介意把它綁定到一個特定的entitymanager,但是tx manazger是一個問題?對於'@ Transactional',你需要指定使用哪一個,以防多個管理者。如果你沒有使用多個''布洛克。 – 2014-09-05 11:35:52

回答

1

這是我的工作配置有2持久化上下文:?

<!-- METADATA --> 

<!-- Metadata connection pool --> 
<bean id="scprMetadataDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
    destroy-method="close"> 
    <property name="driverClass" 
     value="..." /> 
    <property name="jdbcUrl" 
     value="..." /> 
    <property name="user" 
     value="..." /> 
    <property name="password" 
     value="..." /> 
    <property name="maxPoolSize" 
     value="..." /> 
    <property name="minPoolSize" 
     value="..." /> 
</bean> 

<!-- Metadata entity manager factory --> 
<bean id="scprMetadataEntityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="jpaVendorAdapter"> 
     <bean 
      class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> 
      <property name="database" value="H2" /> 
     </bean> 
    </property> 
</bean> 

<!-- Metadata transaction manager --> 
<bean id="scprMetadataTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="scprMetadataEntityManagerFactory" /> 
</bean> 


<!-- DOMAIN --> 

<!-- Domain connection pool --> 
<bean id="scprDomainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
    destroy-method="close"> 
    <property name="driverClass" 
     value="..." /> 
    <property name="jdbcUrl" 
     value="..." /> 
    <property name="user" 
     value="..." /> 
    <property name="password" 
     value="..." /> 
    <property name="maxPoolSize" 
     value="..." /> 
    <property name="minPoolSize" 
     value="..." /> 
</bean> 

<!-- Domain entity manager factory --> 
<bean id="scprDomainEntityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="jpaVendorAdapter"> 
     <bean 
      class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> 
      <property name="database" value="SQL_SERVER" /> 
     </bean> 
    </property> 
</bean> 

<!-- Domain transaction manager --> 
<bean id="scprDomainTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="scprDomainEntityManagerFactory" /> 
</bean> 

其他配置(在你的問題丟失):

<persistence-unit name="scpr_metadata" transaction-type="RESOURCE_LOCAL"> 
    <exclude-unlisted-classes>true</exclude-unlisted-classes> 
    <class>...</class> 
    <class>...</class> 
    <class>...</class> 
</persistence-unit> 

<persistence-unit name="scpr_domain" transaction-type="RESOURCE_LOCAL"> 
    <exclude-unlisted-classes>true</exclude-unlisted-classes> 
    <class>...</class> 
    <class>...</class> 
    <class>...</class> 
</persistence-unit> 

在我的java類:

@Repository 
public final class MetadataRepositoryImpl implements MetadataRepository { 

@PersistenceContext(unitName = "scpr_metadata") 
private EntityManager em; 

和:

@Repository 
public final class DomainRepositoryImpl implements DomainRepository { 

@PersistenceContext(unitName = "scpr_domain") 
private EntityManager em; 

希望這有助於你。

+0

這正是我一直在做的。只是在我的問題中省略了persistence.xml。現在我正在使用的配置已在命令行應用程序中運行。這就是爲什麼我認爲這可能是一個春季啓動配置問題...無論如何謝謝! – achingfingers 2014-09-05 12:29:50

相關問題