복붙노트

[SPRING] Spring 배치에서 여러 데이터 소스 사용

SPRING

Spring 배치에서 여러 데이터 소스 사용

스프링 배치 내에서 몇 가지 데이터 소스를 구성하려고합니다. 시작할 때 Spring Batch는 다음 예외를 throw합니다.

기본 BatchConfigurer를 사용하려면 컨텍스트가 하나의 DataSource 이상을 포함해야하며, 2를 찾았습니다.

일괄 구성에서 미리보기

@Configuration
@EnableBatchProcessing 
public class BatchJobConfiguration {

    @Primary
    @Bean(name = "baseDatasource")
    public DataSource dataSource() {
         // first datasource definition here
    }
    @Bean(name = "secondaryDataSource")
    public DataSource dataSource2() {
         // second datasource definition here
    }
    ...
}

왜 내가 여러 데이터 소스를 선언하는 Spring 배치를위한 XML 기반의 설정을 보았 기 때문에 왜이 예외가 보이는지 확신 할 수 없습니다. 스프링 부트 버전 1.1.5.RELEASE를 사용하여 스프링 배치 코어 버전 3.0.1.RELEASE를 사용하고 있습니다. 어떤 도움이라도 대단히 감사하겠습니다.

해결법

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

    1.AbstractBatchConfiguration은 컨테이너에서 BatchConfigurer를 먼저 찾는다. 찾지 못하면 컨테이너 자체에서 BatchConfigurer를 찾는다. 컨테이너에 둘 이상의 DataSource bean이있는 경우 IllegalStateException이 발생한다.

    AbstractBatchConfiguration은 컨테이너에서 BatchConfigurer를 먼저 찾는다. 찾지 못하면 컨테이너 자체에서 BatchConfigurer를 찾는다. 컨테이너에 둘 이상의 DataSource bean이있는 경우 IllegalStateException이 발생한다.

    이 문제를 해결하기위한 접근 방법은 AbstractBatchConfiguration에서 DefaultBatchConfigurer 빈을 생성하지 못하게하는 것입니다. 이를 위해 @Component 주석을 사용하여 Spring 컨테이너에 의해 DefaultBatchConfigurer를 생성 할 것을 제안한다.

    @EnableBatchProcessing이있는 구성 클래스는 DefaultBatchConfigurer에서 파생 된 빈 클래스가 포함 된 패키지를 검색하는 @ComponentScan으로 주석을 추가 할 수 있습니다.

    package batch_config;
    ...
    @EnableBatchProcessing
    @ComponentScan(basePackageClasses = MyBatchConfigurer.class)
    public class MyBatchConfig {
        ...
    }
    

    빈 파생 클래스의 전체 코드는 다음과 같습니다.

    package batch_config.components;
    import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
    import org.springframework.stereotype.Component;
    @Component
    public class MyBatchConfigurer extends DefaultBatchConfigurer {
    }
    

    이 구성에서 @Primary 주석은 아래 예제와 같이 DataSource bean에서 작동합니다.

    @Configuration
    public class BatchTestDatabaseConfig {
        @Bean
        @Primary
        public DataSource dataSource()
        {
            return .........;
        }
    }
    

    이것은 스프링 배치 버전 3.0.3.RELEASE에서 작동합니다.

    DataSource 작업에서 @Primary 주석을 작성하는 가장 간단한 솔루션은 @EnableBatchProcessing 주석과 함께 @ComponentScan (basePackageClasses = DefaultBatchConfigurer.class)을 추가하는 것일 수 있습니다.

    @Configuration
    @EnableBatchProcessing
    @ComponentScan(basePackageClasses = DefaultBatchConfigurer.class)
    public class MyBatchConfig {
    
  2. ==============================

    2.자신의 BatchConfigurer를 제공해야합니다. 봄은 당신을 위해 그 결정을 내리고 싶지 않습니다.

    자신의 BatchConfigurer를 제공해야합니다. 봄은 당신을 위해 그 결정을 내리고 싶지 않습니다.

    @Configuration
    @EnableBatchProcessing
    public class BatchConfig {
    
         @Bean
          BatchConfigurer configurer(@Qualifier("batchDataSource") DataSource dataSource){
            return new DefaultBatchConfigurer(dataSource);
          }
    
    ...
    
  3. ==============================

    3.가장 간단한 해결책은 DefaultBatchConfigurer를 확장하고 한정자를 통해 데이터 소스를 autowire하는 것입니다.

    가장 간단한 해결책은 DefaultBatchConfigurer를 확장하고 한정자를 통해 데이터 소스를 autowire하는 것입니다.

    @Component
    public class MyBatchConfigurer extends DefaultBatchConfigurer {
    
        /**
         * Initialize the BatchConfigurer to use the datasource of your choosing
         * @param firstDataSource
         */
        @Autowired
        public MyBatchConfigurer(@Qualifier("firstDataSource") DataSource firstDataSource) {
            super(firstDataSource);
        }
    }
    

    사이드 노트 (이것은 여러 데이터 소스의 사용을 다루기 때문에) : autoconfig를 사용하여 데이터 초기화 스크립트를 실행한다면, 기대하는 데이터 소스에서 초기화되지 않은 것을 알 수 있습니다. 그 문제에 관해서는 다음을보십시오 : https://github.com/spring-projects/spring-boot/issues/9528

  4. ==============================

    4.위의 질문에 추가 할 수있는 경우, 각 DS에 대해 하나씩 2 개의 트랜잭션 컨텍스트가 있음을 의미합니다. 단계별로 TXN 관리를 보장해야하므로 일괄 처리와 XA 트랜잭션을 통합하는 방법은 무엇입니까? 요구 사항은 배치 단계에서 다음과 같이 필요합니다.

    위의 질문에 추가 할 수있는 경우, 각 DS에 대해 하나씩 2 개의 트랜잭션 컨텍스트가 있음을 의미합니다. 단계별로 TXN 관리를 보장해야하므로 일괄 처리와 XA 트랜잭션을 통합하는 방법은 무엇입니까? 요구 사항은 배치 단계에서 다음과 같이 필요합니다.

  5. ==============================

    5.@vanarchi가 대답 한 해결책과 매우 흡사 한 해결책을 제시하고자합니다. 그러나 필요한 모든 구성을 하나의 클래스에 넣을 수있었습니다.

    @vanarchi가 대답 한 해결책과 매우 흡사 한 해결책을 제시하고자합니다. 그러나 필요한 모든 구성을 하나의 클래스에 넣을 수있었습니다.

    완전성을 위해 여기의 솔루션은 기본 데이터 소스가 hsql이라고 가정합니다.

    @Configuration
    @EnableBatchProcessing
    public class BatchConfiguration extends DefaultBatchConfigurer {
    
    @Bean
    @Primary
    public DataSource batchDataSource() {
    
        // no need shutdown, EmbeddedDatabaseFactoryBean will take care of this
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase embeddedDatabase = builder
                .addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql")
                .addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql")
                .setType(EmbeddedDatabaseType.HSQL) //.H2 or .DERBY
                .build();
        return embeddedDatabase;
    }
    
    @Override
    protected JobRepository createJobRepository() throws Exception {
        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(batchDataSource());
        factory.setTransactionManager(transactionManager());
        factory.afterPropertiesSet();
    
        return (JobRepository) factory.getObject();
    }
    
    private ResourcelessTransactionManager transactionManager() {
        return new ResourcelessTransactionManager();
    }
    
    //NOTE: the code below is just to provide developer an easy way to access the in-momery hsql datasource, as we configured it to the primary datasource to store batch job related data. Default username : sa, password : ''
    @PostConstruct
    public void getDbManager(){
        DatabaseManagerSwing.main(
                new String[] { "--url", "jdbc:hsqldb:mem:testdb", "--user", "sa", "--password", ""});
    }
    

    }

    이 솔루션의 세 가지 요점 :

  6. ==============================

    6.먼저, 사용자 정의 BatchConfigurer를 작성하십시오.

    먼저, 사용자 정의 BatchConfigurer를 작성하십시오.

    @Configuration
    @Component
    public class TwoDataSourcesBatchConfigurer implements BatchConfigurer {
    
        @Autowired
        @Qualifier("dataSource1")
        DataSource dataSource;
    
        @Override
        public JobExplorer getJobExplorer() throws Exception {
            ...
        }
    
        @Override
        public JobLauncher getJobLauncher() throws Exception {
            ...
        }
    
        @Override
        public JobRepository getJobRepository() throws Exception {
            JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
            // use the autowired data source
            factory.setDataSource(dataSource);
            factory.setTransactionManager(getTransactionManager());
            factory.afterPropertiesSet();
            return factory.getObject();
        }
    
        @Override
        public PlatformTransactionManager getTransactionManager() throws Exception                      {
            ...
        }
    
    }
    

    그때,

    @Configuration
    @EnableBatchProcessing
    @ComponentScan("package")
    public class JobConfig {
        // define job, step, ...
    }
    
  7. from https://stackoverflow.com/questions/25540502/use-of-multiple-datasources-in-spring-batch by cc-by-sa and MIT license