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

查看:18
本文介绍了xml配置中的多个jpa:repositories,如何使用Spring java config配置@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 数据库的 DataSource:

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 config配置@EnableJPARepositories?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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