Spring 数据 JPA - 多个 EnableJpaRepositories
Spring Data JPA - Multiple EnableJpaRepositories
我的应用程序有多个数据源,因此我基于此class创建了两个数据源配置URL。
但是 运行 spring 引导应用程序出现错误
Description:
Field userDataRepo in com.cavion.services.UserDataService required a bean named 'entityManagerFactory' that could not be found.
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
从 Whosebug 上的这个 Question 帮助我弄清楚 issue.i 需要在我的 JPA 存储库上指定 entityManagerFactoryRef 。
但我有很多存储库 classes,其中一些使用 Entitymanager 'A',一些使用 'B'。我当前的 spring 启动应用程序 class 是这样的
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
@EnableTransactionManagement
@EntityScan("com.info.entity")
@ComponentScan({"com.info.services","com.info.restcontroller"})
@EnableJpaRepositories("com.info.repositories")
public class CavionApplication {
public static void main(String[] args) {
SpringApplication.run(CavionApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}}
我已经在 spring 引导 class 上提供了 EnableJpaRepositories,那么如何配置多个 EnableJpaRepositories 以便我可以配置多个 entityManagerFactory?
请建议设置多个数据源的最佳方法。
为了让spring知道什么DataSource
和什么Repository
相关,你应该在@EnableJpaRepositories
注释中定义它。假设我们有两个实体,Servers
实体和 Domains
实体,每个实体都有自己的 Repo,然后每个 Repository 都有自己的 JpaDataSource 配置。
1.根据它们相关的数据源对所有存储库进行分组。例如
Domains
个实体的存储库(包:org.springdemo.multiple.datasources.repository.domains
):
package org.springdemo.multiple.datasources.repository.domains;
import org.springdemo.multiple.datasources.domain.domains.Domains;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DomainsRepository extends JpaRepository<Domains,Long> {
}
Servers
个实体的存储库(包:org.springdemo.multiple.datasources.repository.servers
)
package org.springdemo.multiple.datasources.repository.servers;
import org.springdemo.multiple.datasources.domain.servers.Servers;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ServersRepository extends JpaRepository<Servers,Long> {
}
2。对于每个 JPA 数据源,您需要定义一个配置,在这个例子中,我展示了如何配置两个不同的数据源
Domains
Jpa 配置:数据源和存储库之间的关系在 basePackages
值中定义,这就是为什么需要根据不同的包将存储库分组的原因每个 repo 将使用的实体管理器。
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "domainsEntityManager",
transactionManagerRef = "domainsTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
)
public class DomainsConfig {
Servers
数据源配置:如您所见,basePackages 值具有 Servers
Repository 的包名称,以及 entityManagerFactoryRef
和 transactionManagerRef
的值不同是为了让 spring 将每个 entityManager 分开。
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "serversEntityManager",
transactionManagerRef = "serversTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
)
public class ServersConfig {
3。将一个数据源设为主要
为了避免错误消息:Parameter 0 of constructor in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration required a single bean, but 2 were found:
只需将其中一个数据源设置为@Primary,在本例中我将select Servers
数据源作为主要数据源:
@Bean("serversDataSourceProperties")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties(){
return new DataSourceProperties();
}
@Bean("serversDataSource")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(@Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) {
return serversDataSourceProperties().initializeDataSourceBuilder().build();
}
如果您需要更多信息,请参阅每个配置的完整示例:
Servers
JPA 配置
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "serversEntityManager",
transactionManagerRef = "serversTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
)
public class ServersConfig {
@Bean(name = "serversEntityManager")
public LocalContainerEntityManagerFactoryBean getServersEntityManager(EntityManagerFactoryBuilder builder,
@Qualifier("serversDataSource") DataSource serversDataSource){
return builder
.dataSource(serversDataSource)
.packages("org.springdemo.multiple.datasources.domain.servers")
.persistenceUnit("servers")
.properties(additionalJpaProperties())
.build();
}
Map<String,?> additionalJpaProperties(){
Map<String,String> map = new HashMap<>();
map.put("hibernate.hbm2ddl.auto", "create");
map.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
map.put("hibernate.show_sql", "true");
return map;
}
@Bean("serversDataSourceProperties")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties(){
return new DataSourceProperties();
}
@Bean("serversDataSource")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(@Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) {
return serversDataSourceProperties().initializeDataSourceBuilder().build();
}
@Bean(name = "serversTransactionManager")
public JpaTransactionManager transactionManager(@Qualifier("serversEntityManager") EntityManagerFactory serversEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(serversEntityManager);
return transactionManager;
}
}
Domains
JPA 配置
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "domainsEntityManager",
transactionManagerRef = "domainsTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
)
public class DomainsConfig {
@Bean(name = "domainsEntityManager")
public LocalContainerEntityManagerFactoryBean getdomainsEntityManager(EntityManagerFactoryBuilder builder
,@Qualifier("domainsDataSource") DataSource domainsDataSource){
return builder
.dataSource(domainsDataSource)
.packages("org.springdemo.multiple.datasources.domain.domains")
.persistenceUnit("domains")
.properties(additionalJpaProperties())
.build();
}
Map<String,?> additionalJpaProperties(){
Map<String,String> map = new HashMap<>();
map.put("hibernate.hbm2ddl.auto", "create");
map.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
map.put("hibernate.show_sql", "true");
return map;
}
@Bean("domainsDataSourceProperties")
@ConfigurationProperties("app.datasource.domains")
public DataSourceProperties domainsDataSourceProperties(){
return new DataSourceProperties();
}
@Bean("domainsDataSource")
public DataSource domainsDataSource(@Qualifier("domainsDataSourceProperties") DataSourceProperties domainsDataSourceProperties) {
return domainsDataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean(name = "domainsTransactionManager")
public JpaTransactionManager transactionManager(@Qualifier("domainsEntityManager") EntityManagerFactory domainsEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(domainsEntityManager);
return transactionManager;
}
}
为了分离每个数据源,我将配置放在 application.properties
文件中,如下所示:
app.datasource.domains.url=jdbc:h2:mem:~/test
app.datasource.domains.driver-class-name=org.h2.Driver
app.datasource.servers.driver-class-name=com.mysql.jdbc.Driver
app.datasource.servers.url=jdbc:mysql://localhost:3306/v?autoReconnect=true&useSSL=false
app.datasource.servers.username=myuser
app.datasource.servers.password=mypass
如果您需要更多信息,请参阅以下文档:
Spring Documentation: howto-two-datasources
如何配置两个不同数据库的类似示例:github example
@Daniel C. 提供的答案是正确的。我身边的小correction/observation。
- @Primary 如果您不想将任何数据源标记为
默认一个,否则需要。
- 如果您将 EntityManagerFactoryBean 中的任何一个 @Bean 名称定义为 entityManagerFactory 那么最好标记为@Primary,避免冲突。
- @ConfigurationProperties("app.datasource.servers")
可以在 class 级别标记,而不是在方法级别定义。
- 如果您使用 Spring,最好 return HikariDataSource 作为数据源
启动 2.x 或更高版本,因为它已更改。
- 确保为 jdbc-url 定义精确的 属性
HikariDataSource 引用 JDBC 连接 URL。
我刚刚在 github.Some 中为 mysql 添加了一个模块感知多数据库感知库,需要添加应用程序属性,你就完成了。
可以在以下位置找到文档和其他详细信息:-
https://github.com/yatharthamishra0419/spring-boot-data-multimodule-mysql
我的应用程序有多个数据源,因此我基于此class创建了两个数据源配置URL。
但是 运行 spring 引导应用程序出现错误
Description: Field userDataRepo in com.cavion.services.UserDataService required a bean named 'entityManagerFactory' that could not be found. Action: Consider defining a bean named 'entityManagerFactory' in your configuration.
从 Whosebug 上的这个 Question 帮助我弄清楚 issue.i 需要在我的 JPA 存储库上指定 entityManagerFactoryRef 。
但我有很多存储库 classes,其中一些使用 Entitymanager 'A',一些使用 'B'。我当前的 spring 启动应用程序 class 是这样的
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
@EnableTransactionManagement
@EntityScan("com.info.entity")
@ComponentScan({"com.info.services","com.info.restcontroller"})
@EnableJpaRepositories("com.info.repositories")
public class CavionApplication {
public static void main(String[] args) {
SpringApplication.run(CavionApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}}
我已经在 spring 引导 class 上提供了 EnableJpaRepositories,那么如何配置多个 EnableJpaRepositories 以便我可以配置多个 entityManagerFactory?
请建议设置多个数据源的最佳方法。
为了让spring知道什么DataSource
和什么Repository
相关,你应该在@EnableJpaRepositories
注释中定义它。假设我们有两个实体,Servers
实体和 Domains
实体,每个实体都有自己的 Repo,然后每个 Repository 都有自己的 JpaDataSource 配置。
1.根据它们相关的数据源对所有存储库进行分组。例如
Domains
个实体的存储库(包:org.springdemo.multiple.datasources.repository.domains
):
package org.springdemo.multiple.datasources.repository.domains;
import org.springdemo.multiple.datasources.domain.domains.Domains;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DomainsRepository extends JpaRepository<Domains,Long> {
}
Servers
个实体的存储库(包:org.springdemo.multiple.datasources.repository.servers
)
package org.springdemo.multiple.datasources.repository.servers;
import org.springdemo.multiple.datasources.domain.servers.Servers;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ServersRepository extends JpaRepository<Servers,Long> {
}
2。对于每个 JPA 数据源,您需要定义一个配置,在这个例子中,我展示了如何配置两个不同的数据源
Domains
Jpa 配置:数据源和存储库之间的关系在 basePackages
值中定义,这就是为什么需要根据不同的包将存储库分组的原因每个 repo 将使用的实体管理器。
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "domainsEntityManager",
transactionManagerRef = "domainsTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
)
public class DomainsConfig {
Servers
数据源配置:如您所见,basePackages 值具有 Servers
Repository 的包名称,以及 entityManagerFactoryRef
和 transactionManagerRef
的值不同是为了让 spring 将每个 entityManager 分开。
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "serversEntityManager",
transactionManagerRef = "serversTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
)
public class ServersConfig {
3。将一个数据源设为主要
为了避免错误消息:Parameter 0 of constructor in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration required a single bean, but 2 were found:
只需将其中一个数据源设置为@Primary,在本例中我将select Servers
数据源作为主要数据源:
@Bean("serversDataSourceProperties")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties(){
return new DataSourceProperties();
}
@Bean("serversDataSource")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(@Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) {
return serversDataSourceProperties().initializeDataSourceBuilder().build();
}
如果您需要更多信息,请参阅每个配置的完整示例:
Servers
JPA 配置
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "serversEntityManager",
transactionManagerRef = "serversTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
)
public class ServersConfig {
@Bean(name = "serversEntityManager")
public LocalContainerEntityManagerFactoryBean getServersEntityManager(EntityManagerFactoryBuilder builder,
@Qualifier("serversDataSource") DataSource serversDataSource){
return builder
.dataSource(serversDataSource)
.packages("org.springdemo.multiple.datasources.domain.servers")
.persistenceUnit("servers")
.properties(additionalJpaProperties())
.build();
}
Map<String,?> additionalJpaProperties(){
Map<String,String> map = new HashMap<>();
map.put("hibernate.hbm2ddl.auto", "create");
map.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
map.put("hibernate.show_sql", "true");
return map;
}
@Bean("serversDataSourceProperties")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties(){
return new DataSourceProperties();
}
@Bean("serversDataSource")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(@Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) {
return serversDataSourceProperties().initializeDataSourceBuilder().build();
}
@Bean(name = "serversTransactionManager")
public JpaTransactionManager transactionManager(@Qualifier("serversEntityManager") EntityManagerFactory serversEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(serversEntityManager);
return transactionManager;
}
}
Domains
JPA 配置
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "domainsEntityManager",
transactionManagerRef = "domainsTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
)
public class DomainsConfig {
@Bean(name = "domainsEntityManager")
public LocalContainerEntityManagerFactoryBean getdomainsEntityManager(EntityManagerFactoryBuilder builder
,@Qualifier("domainsDataSource") DataSource domainsDataSource){
return builder
.dataSource(domainsDataSource)
.packages("org.springdemo.multiple.datasources.domain.domains")
.persistenceUnit("domains")
.properties(additionalJpaProperties())
.build();
}
Map<String,?> additionalJpaProperties(){
Map<String,String> map = new HashMap<>();
map.put("hibernate.hbm2ddl.auto", "create");
map.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
map.put("hibernate.show_sql", "true");
return map;
}
@Bean("domainsDataSourceProperties")
@ConfigurationProperties("app.datasource.domains")
public DataSourceProperties domainsDataSourceProperties(){
return new DataSourceProperties();
}
@Bean("domainsDataSource")
public DataSource domainsDataSource(@Qualifier("domainsDataSourceProperties") DataSourceProperties domainsDataSourceProperties) {
return domainsDataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean(name = "domainsTransactionManager")
public JpaTransactionManager transactionManager(@Qualifier("domainsEntityManager") EntityManagerFactory domainsEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(domainsEntityManager);
return transactionManager;
}
}
为了分离每个数据源,我将配置放在 application.properties
文件中,如下所示:
app.datasource.domains.url=jdbc:h2:mem:~/test
app.datasource.domains.driver-class-name=org.h2.Driver
app.datasource.servers.driver-class-name=com.mysql.jdbc.Driver
app.datasource.servers.url=jdbc:mysql://localhost:3306/v?autoReconnect=true&useSSL=false
app.datasource.servers.username=myuser
app.datasource.servers.password=mypass
如果您需要更多信息,请参阅以下文档:
Spring Documentation: howto-two-datasources
如何配置两个不同数据库的类似示例:github example
@Daniel C. 提供的答案是正确的。我身边的小correction/observation。
- @Primary 如果您不想将任何数据源标记为 默认一个,否则需要。
- 如果您将 EntityManagerFactoryBean 中的任何一个 @Bean 名称定义为 entityManagerFactory 那么最好标记为@Primary,避免冲突。
- @ConfigurationProperties("app.datasource.servers") 可以在 class 级别标记,而不是在方法级别定义。
- 如果您使用 Spring,最好 return HikariDataSource 作为数据源 启动 2.x 或更高版本,因为它已更改。
- 确保为 jdbc-url 定义精确的 属性 HikariDataSource 引用 JDBC 连接 URL。
我刚刚在 github.Some 中为 mysql 添加了一个模块感知多数据库感知库,需要添加应用程序属性,你就完成了。
可以在以下位置找到文档和其他详细信息:-
https://github.com/yatharthamishra0419/spring-boot-data-multimodule-mysql