首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多个jpa:repositories in xml config,如何使用Spring java config配置@EnableJPARepositories?

多个jpa:repositories in xml config,如何使用Spring java config配置@EnableJPARepositories?
EN

Stack Overflow用户
提问于 2013-02-22 01:40:31
回答 2查看 20.8K关注 0票数 6

我研究并找到了一个关于如何在多个数据源中使用spring data jpa的explaination and sample code,它指的是在xml配置中配置多个jpa:repositories,如下所示:

代码语言:javascript
复制
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample"
    entity-manager-factory-ref="entityManagerFactory">
    <repository:exclude-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" />
</jpa:repositories>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample"
    entity-manager-factory-ref="entityManagerFactory-2"
    transaction-manager-ref="transactionManager-2">
    <repository:include-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" />
</jpa:repositories>

如何使用java配置和@EnableJpaRepositories注解声明上面的jpa:repositories配置?

注释似乎只支持一组属性(即只支持一个jpa:存储库),并且不可能多次声明注释。

EN

回答 2

Stack Overflow用户

发布于 2013-11-14 19:10:35

我创建了一个“最小的”多数据源项目来帮助我解决如何做到这一点。这里有7个Java类和其他配置,所以我只会在这个答案中发布关键字提取。您可以从GitHub获取完整的项目:https://github.com/gratiartis/multids-demo

该演示设置了两个JPA实体:

代码语言:javascript
复制
@Entity public class Foo { /* Constructors, fields and accessors/mutators */ }
@Entity public class Bar { /* Constructors, fields and accessors/mutators */ }

与这些相关联,我们将创建两个存储库。多亏了Spring Data的强大功能,我们完全可以通过定义扩展JpaRepository的接口来获得一些功能齐全的存储库:

代码语言:javascript
复制
public interface FooRepository extends JpaRepository<Foo, Long> {}
public interface BarRepository extends JpaRepository<Bar, Long> {}

现在我们需要确保每个映射都映射到它自己的数据库中的一个表。

要实现这一点,我们需要两个独立的实体管理器,每个管理器都有不同的数据源。然而,在Spring Java config @Configuration类中,我们只能有一个@EnableJpaRepositories注释,并且每个这样的注释只能引用一个EntityManagerFactory。为此,我们创建了两个独立的@Configuration类: FooConfig和BarConfig。

这些@Configuration类中的每一个都将基于嵌入式HSQL数据库定义一个DataSource:

代码语言:javascript
复制
@Bean(name = "fooDataSource")
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
            .setName("foodb").setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean(name = "barDataSource")
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
            .setName("bardb").setType(EmbeddedDatabaseType.HSQL).build();
}

@Bean(name = "barEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean lef = 
            new LocalContainerEntityManagerFactoryBean();
    lef.setDataSource(dataSource());
    lef.setJpaVendorAdapter(jpaVendorAdapter);
    lef.setPackagesToScan("com.sctrcd.multidsdemo.domain.bar");
    lef.setPersistenceUnitName("barPersistenceUnit");
    lef.afterPropertiesSet();
    return lef.getObject();
}
@Bean(name = "fooEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean lef = 
            new LocalContainerEntityManagerFactoryBean();
    lef.setDataSource(dataSource());
    lef.setJpaVendorAdapter(jpaVendorAdapter);
    lef.setPackagesToScan("com.sctrcd.multidsdemo.domain.foo");
    lef.setPersistenceUnitName("fooPersistenceUnit");
    lef.afterPropertiesSet();
    return lef.getObject();
}

如上所述,每个配置都应该定义一个EntityManagerFactory,它引用自己的dataSource() @Bean方法。它还定义了它所管理的@Entity bean的路径。您需要确保不同数据源的@Entity bean位于不同的包中。

在这一点上,值得注意的是,如果这些配置中的每一个都使用关键持久性bean(即entityManagerFactory)的默认名称,那么Spring将看到有两个具有EntityManager接口的bean,这两个bean具有相同的名称。所以将会选出一个。这会导致错误,例如:

代码语言:javascript
复制
Not an managed type: class com.sctrcd.multidsdemo.domain.bar.Bar

这可以在演示项目的分支中看到:https://github.com/gratiartis/multids-demo/tree/1-unnamed-entitymanager-beans

这是因为在该示例中,Spring连接了与"foodb“数据库相关的bean,而Bar不是该数据库中的实体。不幸的是,BarRepository已经与Foo实体管理器连接起来了。

我们通过在每个config类中命名所有bean来解决这个问题。即

代码语言:javascript
复制
@Bean(name = "fooDataSource") public DataSource dataSource() { .. }
@Bean(name = "fooEntityManager") public EntityManager entityManager() { .. }

此时,如果您要在项目中运行测试,您可能会看到如下警告:

代码语言:javascript
复制
 No bean named 'entityManagerFactory' is defined.

这是因为...击鼓。我们没有默认名称为" EntityManagerFactory“的entityManagerFactory。我们有一个叫做"fooEntityManagerFactory“,另一个叫做"barEntityManagerFactory”。Spring正在寻找具有缺省名称的东西,所以我们需要指示它以不同的方式组合起来。

事实证明,这非常简单。我们只需要为每个@Configuration类在@EnableJpaRepositories注释中放置正确的引用。

代码语言:javascript
复制
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "fooEntityManagerFactory", 
        transactionManagerRef = "fooTransactionManager",
        basePackages = {"com.sctrcd.multidsdemo.integration.repositories.foo"})
public class FooConfig {
    // ...
}

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "barEntityManagerFactory", 
        transactionManagerRef = "barTransactionManager",
        basePackages = { "com.sctrcd.multidsdemo.integration.repositories.bar" })
public class BarConfig {
    // ...
}

正如您所看到的,这些@EnableJpaRepositories注解中的每一个都定义了特定的命名EntityManagerFactory和PlatformTransactionManager。它们还指定了哪些存储库应该与这些bean连接。在本例中,我将存储库放在特定于数据库的包中。也可以通过将includeFilters添加到注释来定义每个单独的存储库,但通过按数据库分离存储库,我相信事情最终应该更具可读性。

此时,您应该有了一个使用Spring数据存储库来管理两个独立数据库中的实体的工作应用程序。请随意从上面的链接获取项目,并运行测试来查看发生的情况。希望这个答案对更多的人有用,因为我已经花了相当多的时间来尽可能用我能管理的最少的代码来做到这一点。欢迎任何对答案或演示项目进行改进的想法。

票数 21
EN

Stack Overflow用户

发布于 2013-03-01 06:16:06

您可以尝试将其放在两个@Configuration类中(每个@Configuration一个@EnableJpaRepositories )。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15008809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档