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

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

问题描述

我研究过并找到了解释和示例代码关于如何使用带有多个数据源的spring数据jpa,这些数据源指的是在xml配置中配置多个jpa:存储库,如下所示:

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>

你们如何申报两者上面的jpa:使用java配置和@EnableJpaRepositories注释的存储库配置?

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

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

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.

此时值得注意的是,如果这些配置中的每一个都使用默认的namings关键持久化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.

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

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.

这是因为... drumroll ...我们没有带默认名称的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和Platfo rmTransactionManager。它们还指定哪些存储库应与这些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.

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

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