복붙노트

[SPRING] 봄 부팅 응용 프로그램에서 여러 데이터베이스에서 테이블이 생성되지 않음

SPRING

봄 부팅 응용 프로그램에서 여러 데이터베이스에서 테이블이 생성되지 않음

나는 스프링 부트 멀티 임차 신청서를 작성 중입니다. 다음과 같이 다중 데이터 소스를 구성했습니다.

application.properties

spring.multitenancy.datasource1.url=jdbc:mysql://localhost:3306/db1
spring.multitenancy.datasource1.username=root
spring.multitenancy.datasource1.password=****
spring.multitenancy.datasource1.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

spring.multitenancy.datasource2.url=jdbc:mysql://localhost:3306/db2
spring.multitenancy.datasource2.username=root
spring.multitenancy.datasource2.password=****
spring.multitenancy.datasource2.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

spring.multitenancy.datasource3.url=jdbc:mysql://localhost:3306/db3
spring.multitenancy.datasource3.username=root
spring.multitenancy.datasource3.password=****
spring.multitenancy.datasource3.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

DataSourceBasedMultiTenantConnectionProviderImpl.java

@Component
public class DataSourceBasedMultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {

    private static final long serialVersionUID = 8168907057647334460L;
    private static final String DEFAULT_TENANT_ID = "tenant_1";

    @Autowired
    private DataSource dataSource1;

    @Autowired
    private DataSource dataSource2;

    @Autowired
    private DataSource dataSource3;

    private Map<String, DataSource> map;

    @PostConstruct
    public void load() {
        map = new HashMap<>();
        map.put("tenant_1", dataSource1);
        map.put("tenant_2", dataSource2);
        map.put("tenant_3", dataSource3);
    }

    @Override
    protected DataSource selectAnyDataSource() {
        return map.get(DEFAULT_TENANT_ID);
    }

    @Override
    protected DataSource selectDataSource(String tenantIdentifier) {
        return map.get(tenantIdentifier);
    }
}

MultitenancyProperties.java

@ConfigurationProperties("spring.multitenancy")
public class MultitenancyProperties {

    @NestedConfigurationProperty
    private DataSourceProperties datasource1;

    @NestedConfigurationProperty
    private DataSourceProperties datasource2;

    @NestedConfigurationProperty
    private DataSourceProperties datasource3;

    public DataSourceProperties getDatasource1() {
        return datasource1;
    }

    public void setDatasource1(DataSourceProperties datasource1) {
        this.datasource1 = datasource1;
    }

    public DataSourceProperties getDatasource2() {
        return datasource2;
    }

    public void setDatasource2(DataSourceProperties datasource2) {
        this.datasource2 = datasource2;
    }

    public DataSourceProperties getDatasource3() {
        return datasource3;
    }

    public void setDatasource3(DataSourceProperties datasource3) {
        this.datasource3 = datasource3;
    }
}

MultiTenancyJpaConfiguration.java

@Configuration
@EnableConfigurationProperties(JpaProperties.class)
public class MultiTenancyJpaConfiguration {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JpaProperties jpaProperties;

    @Autowired
    private MultiTenantConnectionProvider multiTenantConnectionProvider;

    @Autowired
    private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
        Map<String, Object> hibernateProps = new LinkedHashMap<>();
        hibernateProps.putAll(jpaProperties.getHibernateProperties(dataSource));

        hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
        hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
        hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
        hibernateProps.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");

        return builder.dataSource(dataSource).packages(HotelEntity.class.getPackage().getName()).properties(hibernateProps).jta(false).build();
    }
}

응용 프로그램 시작 프로그램

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(MultitenancyProperties.class)
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }
}

부팅 응용 프로그램을 실행하면 모든 테이블이 첫 번째 데이터 소스에서만 만들어집니다. 1) 응용 프로그램 시작시 모든 데이터 소스에서 테이블을 만들려면 어떻게해야합니까? 2) 각 데이터 소스에 대해 연결을 열거 나 닫는 방법을 보는 방법은 무엇입니까? 3) 더 나은 성능을 위해 스프링 부트를 사용하여 멀티 테넌시 응용 프로그램을 구성하는 더 좋은 방법이 있습니까?

해결법

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

    1.@Alex는 다른 EntityManager, TransactionManager 및 데이터 소스가 필요하다고 말했습니다. 여기 내가 어떻게 할 것 인가.

    @Alex는 다른 EntityManager, TransactionManager 및 데이터 소스가 필요하다고 말했습니다. 여기 내가 어떻게 할 것 인가.

    @Configuration
    @EnableJpaRepositories(
        entityManagerFactoryRef = "dataSource1EntityManagerFactory",
        transactionManagerRef = "dataSource1TransactionManager",
        basePackageClasses = dataSource1Repository.class)
    public class DataSource1Config extends SqlConfig{// Put all common code in base class SqlConfig. If not remove it
    
        @Bean
        @Primary
        public DataSource dataSource1() {
            //create dataSource using MultitenancyProperties::getDataSource1
        }
    
        @Primary
        @Bean(name = "dataSource1TransactionManager")
        PlatformTransactionManager dataSource1TransactionManager(EntityManagerFactory dataSource1EntityManagerFactory) {
            JpaTransactionManager txManager = new JpaTransactionManager();
            txManager.setEntityManagerFactory(dataSource1EntityManagerFactory);
            return txManager;
        }
    
        @Primary
        @Bean(name = "dataSource1EntityManagerFactory")
        LocalContainerEntityManagerFactoryBean dataSource1EntityManagerFactory() {
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.setDataSource(dataSource1());
            em.setPackagesToScan(dataSource1Repository.class.getPackage().getName(), dataSource1ModelClass.class.getPackage().getName());
            em.setPersistenceUnitName("dataSource1Db");
    
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setGenerateDdl(false);
            em.setJpaVendorAdapter(vendorAdapter);
            return em;
        }
    }
    

    이렇게 두 개의 다른 클래스를 만들 수 있습니다. @Primary는 데이터 소스, 트랜잭션 관리자 및 entitymanager 중 단 하나의 인스턴스에서만 사용하십시오 (어느 것이 든 상관 없습니다). 주의 할 점은 저장소 클래스가 세 데이터베이스 모두에 대해 다른 패키지에 있는지 확인하십시오.

  2. ==============================

    2.2 개의 다른 퍼시스턴스 팩토리가 필요합니다. 하나는 아니고 각각 다른 데이터 소스에 대해 다른 EntityManagers를 생성해야합니다. 또한 각 엔티티 매핑은 하나의 엔티티 관리자에서만 사용되도록 표시되어야합니다. 전체 솔루션보기 :

    2 개의 다른 퍼시스턴스 팩토리가 필요합니다. 하나는 아니고 각각 다른 데이터 소스에 대해 다른 EntityManagers를 생성해야합니다. 또한 각 엔티티 매핑은 하나의 엔티티 관리자에서만 사용되도록 표시되어야합니다. 전체 솔루션보기 :

    http://www.baeldung.com/spring-data-jpa-multiple-databases

  3. from https://stackoverflow.com/questions/43122329/tables-not-getting-created-in-multiple-databases-in-spring-boot-application by cc-by-sa and MIT license