首页 文章

Spring Data JPA - 多个EnableJpaRepositories

提问于
浏览
10

我的应用程序有多个数据源,因此我基于此URL创建了两个数据源配置类 .

但是在运行spring boot应用程序时遇到错误

描述:com.cavion.services.UserDataService中的字段userDataRepo需要一个名为“entityManagerFactory”的bean,该bean无法找到 . 操作:考虑在配置中定义名为“entityManagerFactory”的bean .

从这个Question开始,StackOverflow帮助我找出问题 . 我需要在我的JPA存储库中指定entityManagerFactoryRef .

但我有许多存储库类,其中一些使用Entitymanager'A',其中一些使用'B' . 我目前的 Spring 季启动应用程序类是这样的

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

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

1 回答

  • 12

    为了让spring知道 DataSource 与你应该在 @EnableJpaRepositories 注释中定义的内容有什么关系 . 假设我们有两个实体, Servers 实体和 Domains 实体,每个实体都有自己的Repo,然后每个Repository都有自己的JpaDataSource配置 .

    1. Group all the repositories based on the Data Source that they are related to. For example

    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. For each JPA Data Soruce you need to define a configuration, in this example I show how to configure two different DataSources

    Domains Jpa配置:数据源和存储库之间的关系在 basePackages 值中定义,这就是为什么必须根据每个存储库将使用的实体管理器将存储库分组到不同的包中的原因 .

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

    Servers 数据源配置:如您所见,basePackages值具有 Servers 存储库的包名称,并且 entityManagerFactoryReftransactionManagerRef 的值也不同,以便让spring分隔每个entityManager .

    @Configuration
    @EnableJpaRepositories(
            entityManagerFactoryRef = "serversEntityManager",
            transactionManagerRef = "serversTransactionManager",
            basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
            )
    public class ServersConfig {
    

    3. Set one Datasource as primary

    为了避免错误消息: Parameter 0 of constructor in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration required a single bean, but 2 were found: 只是将其中一个数据源设置为@Primary,在本例中我选择 Servers Datasource作为主数据:

    @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

相关问题