gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:42:49 24 4
gpt4 key购买 nike

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

<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:repository)并且不可能多次声明注解。

最佳答案

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

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

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

与这些相关联,我们将创建两个存储库。感谢 Spring Data 的强大功能,我们可以仅通过定义扩展 JpaRepository 的接口(interface)来获得一些非常全功能的存储库:

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

现在我们需要确保这些都映射到自己数据库中的表。

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

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

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

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

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 实体管理器。

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

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

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

 No bean named 'entityManagerFactory' is defined.

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

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

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

关于java - 多个 jpa :repositories in xml config, 如何使用 Spring java 配置配置 @EnableJPARepositories?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15008809/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com