Spring Data JPA: 多个数据库/实体管理器配置的存储库

11

我有两个Entitymanager bean配置,每个都指向一个不同模式的单独数据库(一个是Oracle,另一个是内存中的H2)。

我该怎么解决每个Repository使用哪个Entitymanager的歧义?目前我收到了这个错误:

 No unique bean of type [javax.persistence.EntityManagerFactory] is defined:
 expected single bean but found 2

我想我可以提供一个快速解决方案,只需使用类似的东西

<jpa:repositories base-package="com.foo.repos.ora"
 entity-manager-factory-ref="entityManagerFactoryA">

<jpa:repositories base-package="com.foo.repos.m2"
 entity-manager-factory-ref="entityManagerFactoryB">

但希望有更好的解决方案。

编辑:

我向您介绍当前情况的想法:

Spring-Config: 有两个EM

<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/>
<jpa:repositories base-package="com.foo.repos.m2" entity-manager-factory-ref="entityManagerFactory2"/>
<context:component-scan base-package="com.foo" />  ....

从这里开始的一切都在 "package com.foo.repos.ora" 中。 按照 如何创建自定义Repository 的模板,我创建了两个接口'ARepository'、'ARepositoryCustom'和它的实现类'ARepositoryImpl'。

@Repository
public interface ARepository extends ARepositoryCustom, JpaRepository<myEntity, BigDecimal>, QueryDslPredicateExecutor {

}

public interface ARepositoryCustom {
    FooBar lookupFooBar()
}

public class ARepositoryImpl extends QueryDslRepositorySupport implements ARepositoryCustom {
    ARepositoryImpl(Class<?> domainClass) {
        super(domainClass.class)
    }

    ARepositoryImpl() {
        this(myEntity.class)
    }

    @Override
    FooBar lookupFooBar() {
        JPQLQuery query = ....
        ....
        return found
    }
}

导致以下错误信息:

Caused by: org.springframework.beans.factory.BeanCreationException: 创建名为 'aRepositoryImpl' 的bean时出错:注入持久性依赖项失败;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: 没有定义类型为 [javax.persistence.EntityManagerFactory] 的唯一bean:期望单个bean但找到2个

这当然是正确的,存在两个EM bean,但由于我将 EM#1(即'entityManagerFactory')限制为仅适用于包 'com.foo.repos.ora',因此我仍然不确定如何引用确切的EM bean。

1个回答

13

引擎盖下面没有魔法。

<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/>

完全不能帮助你自定义接口实现。我找到的最好方法是将自定义实现视为常规bean来处理。因此,我在我的Spring配置中定义了一个“sharedEntityManager”bean,如下所示:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       ...
</bean>
<bean id="sharedEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
        <property name = "entityManagerFactory" ref="entityManagerFactory"/>
</bean>

之后,我只是将EntityManager注入到我的实现Bean中

<bean id="aRepositoryImpl" class="comm.foo.repos.ora.ARepositoryImpl">
    <property name="entityManager" ref="sharedEntityManager"/>
</bean>

'entity-manager-factory-ref' 属性用于区分不同的实体管理器工厂,但仅适用于普通的 Spring Data Repositories(即仅适用于接口),它并不涉及任何你的实现。

总之:

1)如果您只使用标准的 Spring Data repositories 而没有自定义实现,请使用“entity-manager-factory-ref”属性来区分数据库。

2a)另外,如果您使用了任何自定义实现,请直接将适当的 EntityManager 注入到实现类中。连接是根据您的 Spring XML 配置控制的。出于某种原因,我无法使用 @Autowired 注释和 @Qualifier 引用正确的 EntityManager。 编辑 我刚学会了 @Resource 注释。

@Resource(name =  "sharedEntityManagerA")
EntityManager entityManager


<bean id="sharedEntityManagerA" name="sharedEntityManagerA" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
        <property name = "entityManagerFactory" ref="entityManagerFactory"/>
</bean>

有了这个,选择使用哪个EntityMAnger就变得简单明了。不需要在您的上下文xml中将所有内容都连接起来。

2b) 作为Spring的xml配置的替代方案,您还可以选择

  

@PersistenceContext(unitName =“nameOfPersistenceUnit”)

来注入正确的EntitymanagerFactory

而'nameOfPersistenceUnit'是指您标准的JPA persistence.xml中的持久性

然而,2b)与'QueryDslRepositorySupport'不兼容,因为它需要一个EntityManager实例。但我发现“QueryDslRepositorySupport”并没有提供太多支持,所以我删除了它。


如果您的应用程序上下文中有两个LocalContainerEntityManagerFactoryBean,每个都有自己的persistenceUnitName,那么2b)也可以完美运行。 - Emil Lundberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接