java - Spring 通过 XML Beans 定义注册多个 Hibernate 数据源

标签 java spring hibernate jpa

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

问题:不熟悉 spring xml 配置。注册多个数据源似乎需要多个 EntityManagerFactory,这会导致错误,指出 EntityManagerFactory 不是唯一的。我尝试了两个 EntityManagerFactory 和一个抽象父级,因为我无法添加多个数据源,而不是在entityManagerFactory 定义中添加单个数据源。我该如何解决这个问题?

我无法使用 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;

    ...

beans-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 ...期望单个匹配bean,但发现2:entityManagerFactory,entityManagerFactory-2

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

更新:

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

beans-config.xml:

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

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

最佳答案

您的代码包含两个歧义:

  1. @PersistenceContext 的单元解析。
  2. JpaTransactionManager 的单元解析。

解决 @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>

关于java - Spring 通过 XML Beans 定义注册多个 Hibernate 数据源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44311389/

相关文章:

java - Websphere 6.1集群环境下如何运行定时任务

java - 无法使用 hibernate PostgreSQL 存储 java.time.ZonedDateTime

java - Apache CXF(简单前端): 'Already connected' 中的问题

java - 随机访问文件.write : EBADF (Bad file descriptor)

java - 如何在 WAR 中打包文档工件

java - 如何在 Spring 中使用 @ConfigurationProperties 加载名称值属性

java - IntelliJ 问题 - 无法运行简单的 Spring 应用程序

java - JPA 2.0 (Hibernate) 为 @OneToMany 和 @JoinTable 生成不正确的连接表 PK

java - 将数据从 hibernate 层提取到另一层的最佳方法是什么?

java - 我的实体加载速度超慢有什么问题?