Spring Data JPA - 多个EnableJpaRepositories

Ans*_*mad 19 spring hibernate jpa datasource spring-data-jpa

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

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

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

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

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

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

    };
}}
Run Code Online (Sandbox Code Playgroud)

我在Spring引导类上给出了EnableJpaRepositories,那么如何配置多个EnableJpaRepositories以便我可以配置多个entityManagerFactory?

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

Dan*_* C. 34

为了让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> {
}
Run Code Online (Sandbox Code Playgroud)

存储库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> {
}
Run Code Online (Sandbox Code Playgroud)

2.对于每个JPA Data Soruce,您需要定义配置,在此示例中,我将展示如何配置两个不同的DataSource

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

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

Servers数据源配置:正如你所看到的basePackages值具有的包名Servers库,并且还值entityManagerFactoryReftransactionManagerRef是为了让春天分隔每个EntityManager的不同.

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

3.将一个数据源设置为主数据

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

@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();
}
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

为了分隔每个数据源,我将配置放在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
Run Code Online (Sandbox Code Playgroud)

如果您需要更多信息,请参阅以下文档:

Spring文档:howto-two-datasources

如何配置两个不同的数据库的类似示例:github示例

  • 我能够通过将其中一个类的实体管理器作为主要来解决这个问题 (3认同)
  • 这是您的文章,还是有人只是将 stackoverflow 的答案复制粘贴到其网站上:https://newbedev.com/spring-data-jpa-multiple-enablejparepositories (3认同)
  • 我尝试了这个,但收到错误“考虑在配置中定义'org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder'类型的bean。” 。最初,我收到错误消息,说找不到服务类型的 bean,我希望这是因为新的配置类未加载。所以我已将这两个类导入到主类中。之后我能够执行配置类,但得到上面提到的错误。 (2认同)
  • 我能够通过从 Main class 中删除 HibernateJpaAutoConfiguration 的排除来解决上述问题。但在初始化实体管理器时出现新错误 描述:org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration 中的方法 requestMappingHandlerMapping 需要单个 bean,但找到了 2 个: - ibDemoEntityManager:由 IBDemoConfig 中的方法“getIBDemoEntityManager”定义 - mwDemoEntityManager:由 MWDemoConfig 中的“getServersEntityManager”方法定义 (2认同)