xml 配置中的多个 jpa:repositories,如何使用 Spring java 配置使用 @EnableJPARepositories 进行配置? [英] Multiple jpa:repositories in xml config, how to configure with @EnableJPARepositories using Spring java config?

查看:57
本文介绍了xml 配置中的多个 jpa:repositories,如何使用 Spring java 配置使用 @EnableJPARepositories 进行配置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我研究并发现了一个 说明和示例代码关于如何在多个数据源中使用spring data jpa 指的是在xml配置中配置多个jpa:repositories如下:

I have researched and found an explaination and sample code as to how to use spring data jpa with multiple datasources which refers to configuring multiple jpa:repositories in the xml configuration as follows:

<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 配置?

How would you declare both of the above jpa:repositories configurations using java configuration and the @EnableJpaRepositories annotation?

注解似乎只支持一组属性(即只支持一个 jpa:repository)并且不可能多次声明注解.

The annotation seems to support only one set of attributes (i.e. for one jpa:repository only) and it is not possible to declare the annotation multiple times.

推荐答案

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

I created a 'minimal' multiple datasource project to help me work out how to do this. There are 7 Java classes and other config in there, so I will only post key extracts in this answer. You can get the full project from GitHub: https://github.com/gratiartis/multids-demo

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

The demo sets up two JPA entities:

@Entity public class Foo { /* Constructors, fields and accessors/mutators */ }
@Entity public class Bar { /* Constructors, fields and accessors/mutators */ }

与这些相关联,我们将创建两个存储库.感谢 Spring Data 的强大功能,我们可以纯粹通过定义扩展 JpaRepository 的接口来获得一些功能相当齐全的存储库:

Associated with these we will create two repositories. Thanks to the awesomeness of Spring Data, we can get ourselves some pretty full-featured repositories purely by defining interfaces which extend JpaRepository:

public interface FooRepository extends JpaRepository<Foo, Long> {}
public interface BarRepository extends JpaRepository<Bar, Long> {}

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

Now we need to ensure that each of these maps to a table in its own database.

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

To achieve this, we will need two separate entity managers, each of which has a different datasource. However, in a Spring Java config @Configuration class, we can only have one @EnableJpaRepositories annotation and each such annotation can only reference one EntityManagerFactory. To achieve this, we create two separate @Configuration classes: FooConfig and BarConfig.

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

Each of these @Configuration classes will define a DataSource based on an embedded HSQL database:

@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 在不同的包中.

Each configuration should define an EntityManagerFactory, as above, which references its own dataSource() @Bean method. It also defines a path to the @Entity beans which it manages. You need to make sure that @Entity beans for different data sources are in different packages.

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

At this point it's worth noting that if each of these configurations uses the default namings for key persistence beans (i.e. entityManagerFactory), then Spring will see that there are two beans with the EntityManager interface, both of which have the same name. So one will be chosen. This leads to errors such as:

Not an managed type: class com.sctrcd.multidsdemo.domain.bar.Bar

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

This can be seen in the branch of the demo project here: https://github.com/gratiartis/multids-demo/tree/1-unnamed-entitymanager-beans

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

This is because in that example, Spring has wired up the beans relating to the "foodb" database, and Bar is not an entity in that database. Unfortunately the BarRepository has been wired up with the Foo entity manager.

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

We resolve this issue by naming all our beans in each of config class. i.e.

@Bean(name = "fooDataSource") public DataSource dataSource() { .. }
@Bean(name = "fooEntityManager") public EntityManager entityManager() { .. }

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

At this point if you were to run the tests in the project, you might see warnings such as:

 No bean named 'entityManagerFactory' is defined.

这是因为......鼓声......我们没有默认名称为entityManagerFactory"的EntityManagerFactory.我们有一个叫做fooEntityManagerFactory",另一个叫做barEntityManagerFactory".Spring 正在寻找具有默认名称的东西,因此我们需要指示它以不同的方式连接起来.

This is because ... drumroll ... we do not have an EntityManagerFactory with the default name "entityManagerFactory". We have one called "fooEntityManagerFactory" and another called "barEntityManagerFactory". Spring is looking for something with a default name, so we need to instruct it to wire things up differently.

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

As it turns out, this is incredibly simple to do. We just need to put the correct references in the @EnableJpaRepositories annotation for each @Configuration class.

@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 来按名称定义每个单独的存储库,但通过按数据库隔离存储库,我相信最终应该更易读.

As you can see, each of these @EnableJpaRepositories annotations defines a specific named EntityManagerFactory and PlatformTransactionManager. They also specify which repositories should be wired up with those beans. In the example, I have put the repositories in database-specific packages. It is also possible to define each individual repository by name, by adding includeFilters to the annotation, but by segregating the repositories by database, I believe that things should end up more readable.

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

At this point you should have a working application using Spring Data repositories to manage entities in two separate databases. Feel free to grab the project from the link above and run the tests to see this happening. Hopefully this answer is useful to more folks, as I have spent a decent amount of time working out to do this as cleanly as possible with as little code as I could manage. Any ideas for improvement of the answer or demo project are welcome.

这篇关于xml 配置中的多个 jpa:repositories,如何使用 Spring java 配置使用 @EnableJPARepositories 进行配置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆