복붙노트

[SPRING] 스프링 배치 데이터와 비즈니스 데이터를위한 별도의 데이터 소스를 java-configure하는 방법은 무엇입니까? 심지어해야합니까?

SPRING

스프링 배치 데이터와 비즈니스 데이터를위한 별도의 데이터 소스를 java-configure하는 방법은 무엇입니까? 심지어해야합니까?

저의 주요 업무는 읽기 작업 만하고 다른 하나는 작문을하지만 트랜잭션을 무시하는 MyISAM 엔진에서는 트랜잭션 지원이 필요하지 않습니다. Spring Batch가 비즈니스 데이터를 보유하고있는 JobRepository와는 별도의 자체 데이터 소스를 갖도록 어떻게 구성 할 수 있습니까? 초기 데이터 소스 설정은 다음과 같이 이루어집니다 :

@Configuration
public class StandaloneInfrastructureConfiguration {

    @Autowired
    Environment env;

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
      LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
      em.setDataSource(dataSource());
      em.setPackagesToScan(new String[] { "org.podcastpedia.batch.*" });

      JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
      em.setJpaVendorAdapter(vendorAdapter);
      em.setJpaProperties(additionalJpaProperties());

      return em;
    }

    Properties additionalJpaProperties() {
          Properties properties = new Properties();
          properties.setProperty("hibernate.hbm2ddl.auto", "none");
          properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
          properties.setProperty("hibernate.show_sql", "true");

          return properties;
    }

    @Bean
    public DataSource dataSource(){

       return DataSourceBuilder.create()
                .url(env.getProperty("db.url"))
                .driverClassName(env.getProperty("db.driver"))
                .username(env.getProperty("db.username"))
                .password(env.getProperty("db.password"))
                .build();          
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(emf);

      return transactionManager;
    }
}

@EnableBatchProcessing 어노테이션이이를 자동으로 사용하는 Job 구성 클래스에 가져옵니다. 내 생각 엔 DefaultBatchConfigurer를 확장하는 구성 클래스를 설정하려고했지만 그 다음에는

@Configuration
@EnableBatchProcessing
@Import({StandaloneInfrastructureConfiguration.class, NotifySubscribersServicesConfiguration.class})
public class NotifySubscribersJobConfiguration extends DefaultBatchConfigurer {

    @Autowired
    private JobBuilderFactory jobBuilders;

    @Autowired
    private StepBuilderFactory stepBuilders;

    @Autowired
    private DataSource dataSource;

    @Autowired
    Environment env;

    @Override
    @Autowired
    public void setDataSource(javax.sql.DataSource dataSource) {
        super.setDataSource(batchDataSource());
    }

    private DataSource batchDataSource(){          
       return DataSourceBuilder.create()
                .url(env.getProperty("batchdb.url"))
                .driverClassName(env.getProperty("batchdb.driver"))
                .username(env.getProperty("batchdb.username"))
                .password(env.getProperty("batchdb.password"))
                .build();          
    } 

    @Bean
    public ItemReader<User> notifySubscribersReader(){

        JdbcCursorItemReader<User> reader = new JdbcCursorItemReader<User>();
        String sql = "select * from users where is_email_subscriber is not null";

        reader.setSql(sql);
        reader.setDataSource(dataSource);
        reader.setRowMapper(rowMapper());       

        return reader;
    }
........
}   

어떤 생각이라도 환영받는 것 이상입니다. 이 프로젝트는 GitHub에서 사용할 수 있습니다 - https://github.com/podcastpedia/podcastpedia-batch

무리 감사.

해결법

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

    1.좋아, 이것은 이상하지만 작동한다. 데이터 소스를 자신의 구성 클래스로 옮기는 것만으로도 잘 작동하며 하나는 자동 응답 할 수 있습니다.

    좋아, 이것은 이상하지만 작동한다. 데이터 소스를 자신의 구성 클래스로 옮기는 것만으로도 잘 작동하며 하나는 자동 응답 할 수 있습니다.

    예제는 스프링 배치 서비스 예제의 다중 데이터 소스 버전입니다.

    DataSourceConfiguration :

    public class DataSourceConfiguration {
    
        @Value("classpath:schema-mysql.sql")
        private Resource schemaScript;
    
        @Bean
        @Primary
        public DataSource hsqldbDataSource() throws SQLException {
            final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
            dataSource.setDriver(new org.hsqldb.jdbcDriver());
            dataSource.setUrl("jdbc:hsqldb:mem:mydb");
            dataSource.setUsername("sa");
            dataSource.setPassword("");
            return dataSource;
        }
    
        @Bean
        public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    
        @Bean
        public DataSource mysqlDataSource() throws SQLException {
            final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
            dataSource.setDriver(new com.mysql.jdbc.Driver());
            dataSource.setUrl("jdbc:mysql://localhost/spring_batch_example");
            dataSource.setUsername("test");
            dataSource.setPassword("test");
            DatabasePopulatorUtils.execute(databasePopulator(), dataSource);
            return dataSource;
        }
    
        @Bean
        public JdbcTemplate mysqlJdbcTemplate(@Qualifier("mysqlDataSource") final DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    
        private DatabasePopulator databasePopulator() {
            final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
            populator.addScript(schemaScript);
            return populator;
        }
    }
    

    배치 구성 :

    @Configuration
    @EnableBatchProcessing
    @Import({ DataSourceConfiguration.class, MBeanExporterConfig.class })
    public class BatchConfiguration {
    
        @Autowired
        private JobBuilderFactory jobs;
    
        @Autowired
        private StepBuilderFactory steps;
    
        @Bean
        public ItemReader<Person> reader() {
            final FlatFileItemReader<Person> reader = new FlatFileItemReader<Person>();
            reader.setResource(new ClassPathResource("sample-data.csv"));
            reader.setLineMapper(new DefaultLineMapper<Person>() {
                {
                    setLineTokenizer(new DelimitedLineTokenizer() {
                        {
                            setNames(new String[] { "firstName", "lastName" });
                        }
                    });
                    setFieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {
                        {
                            setTargetType(Person.class);
                        }
                    });
                }
            });
            return reader;
        }
    
        @Bean
        public ItemProcessor<Person, Person> processor() {
            return new PersonItemProcessor();
        }
    
        @Bean
        public ItemWriter<Person> writer(@Qualifier("mysqlDataSource") final DataSource dataSource) {
            final JdbcBatchItemWriter<Person> writer = new JdbcBatchItemWriter<Person>();
            writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Person>());
            writer.setSql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)");
            writer.setDataSource(dataSource);
            return writer;
        }
    
        @Bean
        public Job importUserJob(final Step s1) {
            return jobs.get("importUserJob").incrementer(new RunIdIncrementer()).flow(s1).end().build();
        }
    
        @Bean
        public Step step1(final ItemReader<Person> reader,
                final ItemWriter<Person> writer, final ItemProcessor<Person, Person> processor) {
            return steps.get("step1")
                    .<Person, Person> chunk(1)
                    .reader(reader)
                    .processor(processor)
                    .writer(writer)
                    .build();
        }
    }
    
  2. ==============================

    2.데이터 소스는 별도의 구성 클래스에 있습니다. 배치 구성에서 DefaultBatchConfigurer를 확장하고 setDataSource 메소드를 재정 의하여 Spring Batch와 함께 @Qualifier와 함께 사용할 특정 데이터베이스를 전달합니다. 이 생성자 버전을 사용하여 작동시키지 못했습니다,하지만 setter 메서드를 나를 위해 일했다.

    데이터 소스는 별도의 구성 클래스에 있습니다. 배치 구성에서 DefaultBatchConfigurer를 확장하고 setDataSource 메소드를 재정 의하여 Spring Batch와 함께 @Qualifier와 함께 사용할 특정 데이터베이스를 전달합니다. 이 생성자 버전을 사용하여 작동시키지 못했습니다,하지만 setter 메서드를 나를 위해 일했다.

    My Reader, Processor 및 Writer 's는 단계와 함께 자체 포함 된 클래스에 있습니다.

    이것은 Spring Boot 1.1.8과 Spring Batch 3.0.1을 사용하고 있습니다. 참고 : 우리는 새로운 버전에서 동일하게 작동하지 않는 Spring Boot 1.1.5를 사용하는 프로젝트에 대해 다른 설정을했습니다.

    package org.sample.config.jdbc;
    
    import javax.sql.DataSource;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.env.Environment;
    
    import com.atomikos.jdbc.AtomikosDataSourceBean;
    import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
    
    /**
     * The Class DataSourceConfiguration.
     *
     */
    @Configuration
    public class DataSourceConfig {
    
        private final static Logger log = LoggerFactory.getLogger(DataSourceConfig.class);
    
        @Autowired private Environment env;
    
        /**
         * Siphon data source.
         *
         * @return the data source
         */
        @Bean(name = "mainDataSource")
        @Primary
        public DataSource mainDataSource() {
    
            final String user = this.env.getProperty("db.main.username");
            final String password = this.env.getProperty("db.main.password");
            final String url = this.env.getProperty("db.main.url");
    
            return this.getMysqlXADataSource(url, user, password);
        }
    
        /**
         * Batch data source.
         *
         * @return the data source
         */
        @Bean(name = "batchDataSource", initMethod = "init", destroyMethod = "close")
        public DataSource batchDataSource() {
    
            final String user = this.env.getProperty("db.batch.username");
            final String password = this.env.getProperty("db.batch.password");
            final String url = this.env.getProperty("db.batch.url");
    
            return this.getAtomikosDataSource("metaDataSource", this.getMysqlXADataSource(url, user, password));
        }
    
        /**
         * Gets the mysql xa data source.
         *
         * @param url the url
         * @param user the user
         * @param password the password
         * @return the mysql xa data source
         */
        private MysqlXADataSource getMysqlXADataSource(final String url, final String user, final String password) {
    
            final MysqlXADataSource mysql = new MysqlXADataSource();
            mysql.setUser(user);
            mysql.setPassword(password);
            mysql.setUrl(url);
            mysql.setPinGlobalTxToPhysicalConnection(true);
    
            return mysql;
        }
    
        /**
         * Gets the atomikos data source.
         *
         * @param resourceName the resource name
         * @param xaDataSource the xa data source
         * @return the atomikos data source
         */
        private AtomikosDataSourceBean getAtomikosDataSource(final String resourceName, final MysqlXADataSource xaDataSource) {
    
            final AtomikosDataSourceBean atomikos = new AtomikosDataSourceBean();
            atomikos.setUniqueResourceName(resourceName);
            atomikos.setXaDataSource(xaDataSource);
            atomikos.setMaxLifetime(3600);
            atomikos.setMinPoolSize(2);
            atomikos.setMaxPoolSize(10);
    
            return atomikos;
        }
    
    }
    
    
    package org.sample.settlement.batch;
    
    import javax.sql.DataSource;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.batch.core.Job;
    import org.springframework.batch.core.Step;
    import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
    import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
    import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
    import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
    import org.springframework.batch.core.launch.support.RunIdIncrementer;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.PlatformTransactionManager;
    
    /**
     * The Class BatchConfiguration.
     *
     */
    @Configuration
    @EnableBatchProcessing
    public class BatchConfiguration extends DefaultBatchConfigurer {
        private final static Logger log = LoggerFactory.getLogger(BatchConfiguration.class);
        @Autowired private JobBuilderFactory jobs;
        @Autowired private StepBuilderFactory steps;
        @Autowired private PlatformTransactionManager transactionManager;
        @Autowired @Qualifier("processStep") private Step processStep;
    
        /**
         * Process payments job.
         *
         * @return the job
         */
        @Bean(name = "processJob")
        public Job processJob() {
            return this.jobs.get("processJob")
                        .incrementer(new RunIdIncrementer())
                        .start(processStep)
                        .build();
        }
    
        @Override
        @Autowired
        public void setDataSource(@Qualifier("batchDataSource") DataSource batchDataSource) {
            super.setDataSource(batchDataSource);
        }
    }
    
  3. ==============================

    3.이런 식으로 이미 시도해 봤니?

    이런 식으로 이미 시도해 봤니?

    @Bean(name="batchDataSource")
    public DataSource batchDataSource(){          
           return DataSourceBuilder.create()
                    .url(env.getProperty("batchdb.url"))
                    .driverClassName(env.getProperty("batchdb.driver"))
                    .username(env.getProperty("batchdb.username"))
                    .password(env.getProperty("batchdb.password"))
                    .build();          
    } 
    

    다른 데이터 소스를 @Primary로 표시하고 배치 구성에서 @Qualifier를 사용하여 batchDataSource bean을 와이어 링하도록 지정하십시오.

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

    4.https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources의 경우 :

    https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources의 경우 :

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource.first")
    public DataSourceProperties firstDataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Bean
    @Primary
    @ConfigurationProperties("app.datasource.first")
    public DataSource firstDataSource() {
        return firstDataSourceProperties().initializeDataSourceBuilder().build();
    }
    
    @Bean
    @ConfigurationProperties("app.datasource.second")
    public DataSourceProperties secondDataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Bean
    @ConfigurationProperties("app.datasource.second")
    public DataSource secondDataSource() {
        return secondDataSourceProperties().initializeDataSourceBuilder().build();
    }
    

    응용 프로그램 속성에서 일반 데이터 소스 속성을 사용할 수 있습니다.

    app.datasource.first.type=com.zaxxer.hikari.HikariDataSource
    app.datasource.first.maximum-pool-size=30
    
    app.datasource.second.url=jdbc:mysql://localhost/test
    app.datasource.second.username=dbuser
    app.datasource.second.password=dbpass
    app.datasource.second.max-total=30
    
  5. ==============================

    5.두 개의 데이터 소스가 있다고 가정하면, 작업 세부 정보와 같은 스프링 배치 메타 데이터 ([CONFIGDB]라고 말하면 됨)와 비즈니스 데이터에 대한 기타 [AppDB]라고합니다.

    두 개의 데이터 소스가 있다고 가정하면, 작업 세부 정보와 같은 스프링 배치 메타 데이터 ([CONFIGDB]라고 말하면 됨)와 비즈니스 데이터에 대한 기타 [AppDB]라고합니다.

    CONFIGDB를 jobRepository에 다음과 같이 삽입하십시오.

     <bean id="jobRepository"
        class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
        <property name="transactionManager" ref="transactionManager" />
        <property name="dataSource" ref="CONFIGDB" />
        <property name="databaseType" value="db2" />
        <property name="tablePrefix" value="CONFIGDB.BATCH_" />
      </bean>
    

    이제 AppDB 다르 타 소스를 DAO 또는 OR Writer에 삽입 할 수 있습니다.

       <bean id="DemoItemWriter" class="com.demoItemWriter">
         <property name="dataSource" ref="AppDB" />     
       </bean>
    

    또는

    당신은 리소스를 정의 할 수 있고 클래스에서 jndi lookup으로이 AppDB를 주입한다.

    public class ExampleDAO {
    
    @Resource(lookup = "java:comp/env/jdbc/AppDB")
    DataSource ds;
    

    }

  6. from https://stackoverflow.com/questions/25256487/how-to-java-configure-separate-datasources-for-spring-batch-data-and-business-da by cc-by-sa and MIT license