【问题标题】:Spring Data JPA - Multiple EnableJpaRepositoriesSpring Data JPA - 多个 EnableJpaRepositories
【发布时间】:2018-01-21 14:43:55
【问题描述】:

我的应用程序有多个数据源,所以我基于这个URL创建了两个数据源配置类。

但是在运行 spring boot 应用程序时出现错误

说明: com.cavion.services.UserDataService 中的字段 userDataRepo 需要找不到名为“entityManagerFactory”的 bean。 行动: 考虑在您的配置中定义一个名为“entityManagerFactory”的 bean。

从 StackOverflow 上的 Question 帮助我找出问题。我需要在我的 JPA 存储库中指定 entityManagerFactoryRef。

但是我有很多存储库类,其中一些使用 Entitymanager 'A' ,其中一些使用 'B' 。我目前的spring boot应用类是这样的

@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 boot 类上给出了 EnableJpaRepositories ,那么如何配置多个 EnableJpaRepositories 以便我可以配置多个 entityManagerFactory ?

请建议设置多个数据源的最佳方法。

【问题讨论】:

    标签: spring hibernate jpa spring-data-jpa datasource


    【解决方案1】:

    我刚刚在github中为mysql添加了一个模块感知多数据库感知库。需要添加一些应用程序属性,你就完成了。

    可以在以下位置找到文档和其他详细信息:-

    https://github.com/yatharthamishra0419/spring-boot-data-multimodule-mysql

    【讨论】:

      【解决方案2】:

      @Daniel C. 提供的答案是正确的。我这边的小修正/观察。

      • 如果您不想将任何数据源标记为,则不需要 @Primary 默认一个,否则需要。
      • 如果您将任何具有 @Bean 名称的 EntityManagerFactoryBean 定义为 entityManagerFactory,那么最好将其标记为 @Primary 以避免冲突。
      • @ConfigurationProperties("app.datasource.servers") 可以在类级别进行标记,而不是在方法级别进行定义。
      • 如果您使用 Spring,最好将 HikariDataSource 作为数据源返回 引导 2.x 或更高版本,因为它已更改。
      • 确保为 jdbc-url 定义准确的属性 HikariDataSource 引用 JDBC 连接 URL。

      【讨论】:

        【解决方案3】:

        为了让spring知道DataSourceRepository的关系,你应该在@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 值中定义,这就是为什么需要根据每个存储库将要使用的实体管理器将存储库分组到不同包中的原因采用。

        @Configuration
        @EnableJpaRepositories(
                entityManagerFactoryRef = "domainsEntityManager",
                transactionManagerRef = "domainsTransactionManager",
                basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
                )
        public class DomainsConfig {
        

        Servers 数据源配置:如您所见,basePackages 值具有Servers Repository 的包名称,并且entityManagerFactoryReftransactionManagerRef 的值也不同,以便让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,在此示例中,我选择 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();
        }
        

        如果您需要更多信息,请查看每个配置的完整示例:

        ServersJPA 配置

        @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;
            }
        }
        

        DomainsJPA 配置

        @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

        【讨论】:

        • 我试过这个,但我收到错误“考虑在你的配置中定义一个 'org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder' 类型的 bean。” .最初我收到错误说找不到服务类型的bean我希望那是因为没有加载新的配置类。所以我已将这两个类导入主类。之后我能够执行配置类但得到上面提到的错误。
        • 我能够通过从 Main class 中删除 HibernateJpaAutoConfiguration 的排除来解决上述问题。但是在初始化 entitymanagers 时出现新错误 说明:org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration 中的方法 requestMappingHandlerMapping 需要一个 bean,但找到了 2 个:-ibDemoEntityManager:由 IBDemoConfig-mwDemoEntityManager 中的方法“getIBDemoEntityManager”定义:由 MWDemoConfig 中的“getServersEntityManager”方法定义
        • 我能够通过将其中一个类的 entitymanager 设为主要来解决问题
        • 好的,我还添加了该观察以使其中一个数据源成为主要数据源。
        • 在运行 springboot 项目时,我的实体类不断收到“非托管类型”。有什么想法吗?
        猜你喜欢
        • 1970-01-01
        • 2018-10-25
        • 2016-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-04
        • 2016-10-21
        • 2016-01-31
        相关资源
        最近更新 更多