Spring通过XML Beans-Definition注册多个Hibernate-Datasources

时间:2017-06-01 15:16:07

标签: java spring hibernate jpa

目标:通过@PersistenceContext访问多个持久性单元/数据源。

问题:Spring xml配置不流畅。注册多个数据源似乎需要多个EntityManagerFactories,然后导致错误,说明EntityManagerFactory不是唯一的。我尝试了两个带有抽象父类的EntityManagerFactories,因为我无法在entityManagerFactory定义中添加多个数据源 s 而不是单个数据源。我该如何解决这个问题?

我无法使用SpringBoot或JpaRepositories。 Spring-jdbc和orm与4.3.4.RELEASE版本一起使用,spring-data-jpa版本为1.10.5.RELEASE。

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'aDaoImpl': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:357)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1219)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:754)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 24 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1034)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:981)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:579)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:546)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:707)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:680)
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354)
    ... 40 more

从服务到数据库的当前路径包含以下文件。请注意,这仅显示一个数据源的尝试。一旦上述错误得到解决,将添加另一个。

道:

public class Dao {

    @PersistenceContext(name= "puName") // tried unitName=... as well
    protected EntityManager em;

    ...

使用Dao的测试:

@ContextConfiguration("classpath:beans-context.xml")
public class DaoTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    private Dao testable;

    @PersistenceContext(name= "puName") // tried unitName=... as well
    protected EntityManager em;

    ...

豆-config.xml中:

...
<import resource="db-context.xml"/>
...

DB-context.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>
    <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:test2;DB_CLOSE_DELAY=-1"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>

    <bean id="entityManagerFactory" parent="abstractEntityManagerFactory">
        <property name="dataSource" ref="dataSource1"/>
        <property name="persistenceUnitName" value="puName"/>
    </bean>
    <!-- this causes the NoUniqueBeanDefinitionException -->
    <bean id="entityManagerFactory-2" parent="abstractEntityManagerFactory">
        <property name="dataSource" ref="dataSource2"/>
        <property name="persistenceUnitName" value="puName2"/>
    </bean>

    <bean id="abstractEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
            abstract="true">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/>
            </bean>
        </property>
    </bean>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>

</beans>

更新

我尝试添加@Qualifier,但我仍然是NoUniqueBeanDefinitionException ... expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2

@PersistenceContext(name = "puName")
@Qualifier("entityManagerFactory")
protected EntityManager em;

更新

使用组件扫描扩展spring-config不会更改错误。

豆-config.xml中:

<context:component-scan annotation-config="true" base-package="path.to.package"/>
<import resource="db-context.xml"/>

更新: 方法注入而不是字段注入不会改变错误。

1 个答案:

答案 0 :(得分:2)

您的代码包含两个含糊之处:

  1. @PersistenceContext的单位分辨率。
  2. JpaTransactionManager的单位分辨率。
  3. 解决@PersistenceContext使用的歧义  @PersistenceContext(unitName = …)代替@PersistenceContext(name = …)

    @PersistenceContext(unitName = "puName")
    protected EntityManager em1;
    
    @PersistenceContext(unitName = "puName2")
    protected EntityManager em2;
    

    JpaTransactionManager还需要提示,否则初始化将失败

    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1034)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
        at org.springframework.orm.jpa.EntityManagerFactoryUtils.findEntityManagerFactory(EntityManagerFactoryUtils.java:143)
        at org.springframework.orm.jpa.JpaTransactionManager.setBeanFactory(JpaTransactionManager.java:292)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1602)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
        ... 38 more
    

    因此,解决歧义的一种方法是设置persistenceUnitName

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="persistenceUnitName" value="puName" />
    </bean>