복붙노트

[SPRING] Spring 데이터 JPA - 다중 EnableJpaRepositories

SPRING

Spring 데이터 JPA - 다중 EnableJpaRepositories

내 응용 프로그램에는 여러 데이터 소스가 있으므로이 URL을 기반으로 두 가지 데이터 소스 구성 클래스를 만들었습니다.

그러나 봄 부팅 응용 프로그램을 실행하는 동안 오류가 발생합니다.

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

    };
}}

Spring 부트 클래스에서 EnableJpaRepositories를주었습니다. 그래서 어떻게 여러 개의 EnableManagerpage를 구성하여 여러 개의 entityManagerFactory를 구성 할 수 있습니까?

여러 데이터 소스를 설정하는 가장 좋은 방법을 제안하십시오.

해결법

  1. ==============================

    1.Spring이 어떤 DataSource가 어떤 저장소와 관련되어 있는지를 알 수 있도록 @EnableJpaRepositories 주석에서 정의해야한다. 서버 엔티티와 도메인 엔티티의 두 엔티티가 있고 각 엔티티에는 자체 Repo가 있고 각 리포지토리에 자체 JpaDataSource 구성이 있다고 가정 해 봅니다.

    Spring이 어떤 DataSource가 어떤 저장소와 관련되어 있는지를 알 수 있도록 @EnableJpaRepositories 주석에서 정의해야한다. 서버 엔티티와 도메인 엔티티의 두 엔티티가 있고 각 엔티티에는 자체 Repo가 있고 각 리포지토리에 자체 JpaDataSource 구성이 있다고 가정 해 봅니다.

    1. 관련된 모든 데이터 소스를 기반으로 모든 리포지토리를 그룹화합니다. 예를 들어

    도메인 엔티티 저장소 (package : 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> {
    }
    

    서버 저장소 용 엔티티 (패키지 : 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 데이터 소스에 대해 구성을 정의해야합니다.이 예에서는 두 개의 다른 데이터 소스를 구성하는 방법을 보여줍니다

    도메인 Jpa 구성 : 데이터 소스와 저장소 간의 관계가 basePackages 값에 정의됩니다. 즉, 각 저장소가 사용할 엔터티 관리자에 따라 저장소를 여러 패키지로 그룹화해야하는 이유입니다.

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

    서버 데이터 소스 설정 : basePackages 값은 Servers Repository의 패키지 이름을 가지며, entityManagerFactoryRef와 transactionManagerRef의 값은 Spring이 각 entityManager를 분리하도록하기 위해 서로 다릅니다.

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

    3. 하나의 데이터 소스를 기본 데이터로 설정하십시오.

    에러 메시지를 피하기 위해서 : org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration에있는 생성자의 파라미터 0은 하나의 빈을 요구했지만 2 개가 발견되었습니다 : 데이터 소스 중 하나를 @Primary로 설정합니다,이 예제에서는 서버 데이터 소스를 기본으로 선택하십시오.

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

    자세한 정보가 필요하면 각 구성에 대한 전체 예제를 참조하십시오.

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

    도메인 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 문서 : howto-two-datasources

    두 개의 서로 다른 데이터베이스를 구성하는 방법과 비슷한 예 : github 예제

  2. from https://stackoverflow.com/questions/45663025/spring-data-jpa-multiple-enablejparepositories by cc-by-sa and MIT license