web-dev-qa-db-ja.com

Spring BatchとJPAとのSpring Boot統合

Spring BootプロジェクトとSpring BatchおよびData JPAプロジェクトを統合しています。ジョブライターの結果をデータベースに永続化することを除いて、ジョブとデータ構成に関連するすべてのものは正しいです。ファイルを読み取って処理した後、mysqlデータベースに書き込むことができません。エラーはありませんが、挿入もありません。興味深いのは、データソースが構成されていることです。を挿入する前に、データベースからサンプルレコードをフェッチできます。この問題の解決を手伝ってください。

私のapplication.properties:

spring.datasource.url = jdbc:mysql://localhost:3306/batchtest?  characterEncoding=UTF-8&autoReconnect=true
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

バッチ構成:

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;

@Bean
public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
}

@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
    MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager);
    mapJobRepositoryFactoryBean.setTransactionManager(transactionManager);
    return mapJobRepositoryFactoryBean.getObject();
}

@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
    SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
    simpleJobLauncher.setJobRepository(jobRepository);
    return simpleJobLauncher;
}
@Bean
public FlatFileItemReader<Person> reader() {
    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 PersonItemProcessor processor() {
    return new PersonItemProcessor();
}
@Bean
public ItemWriter<Person> writer() throws Exception {
    return new PersonWriter();
}
@Bean
public Job importUserJob() throws Exception{
    return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .flow(step1())
            .end()
            .build();
}
 @Bean
public Step step1() throws Exception{
    return stepBuilderFactory.get("step1")
            .<Person, Person> chunk(1)
            .reader(reader())
            .processor(processor())
            .writer(writer())
            .build();
}

ダオクラス:

public interface PersonDao extends CrudRepository<Person,Integer> {
}

ライタークラス:

public class PersonWriter implements ItemWriter<Person> {
@Autowired
PersonDao personDao;

@Override
public void write(List<? extends Person> items) throws Exception {
    LOGGER.info("Received the information of {} students", items.size());
    for(Person person:items)
    {
        LOGGER.info(String.format("inserting for customre %s %s", person.getFirstName(), person.getLastName()));
        Person tempPerson = personDao.findOne(1);
        personDao.save(person) ;
        LOGGER.info(String.format("person id : %d",person.getId()));
    }

}

tempPersonは、JPAデータをテストするためのオブジェクトです。 id 1の人物オブジェクトをデータベースからフェッチしますが、次の行ではデータベースにエラーなしで挿入されていません。行を実行してループを続行します。

14
kaveh.n

この問題の解決策は、予想よりも近いかもしれません。あなたは単にtransactionManager Beanの名前を変更しようとしたのですか?別の名前では、Spring Data JPAではデフォルトで使用されません。

私はあなたの問題を再現し、次にこれから単に切り替えました:

@Bean
public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
}

これに:

@Bean
public ResourcelessTransactionManager resourcelessTransactionManager() {
    return new ResourcelessTransactionManager();
}

そして、私の意見では問題を解決しました。 'transactionManager'は、Spring Data JPAのtransactionManagerのデフォルトのBean名であることを覚えておいてください(少なくとも私が理解している限り、Spring Bootは、その名前のBeanが見つからない限り、自動構成します。 -そしてあなたのデータベーストランザクションはResourcelessのものを通過しています)。

これをスキップすることもできます:

@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
    return new MapJobRepositoryFactoryBean(transactionManager).getObject();
}

そして、Beanを直接呼び出します(Batchで適切なトランザクションマネージャが使用されていることを「確認」するため)。

@Bean
public JobRepository jobRepository() throws Exception {
    return new MapJobRepositoryFactoryBean(resourcelessTransactionManager()).getObject();
}

テストするときに教えてください、そしてそれが主な問題だったことを願っています:)

4
patrykos91

見逃したかもしれませんが、使用しているDBアクセス方法(JPA、Hibernate、JDBCなど)をどこに指定するのかわかりません。私はJPAを想定していますが、ItemWriterはDB対応のItemWriters( RepositoryItemWriterJpaItemWriterJdbcBatchItemWriter 、- HibernateItemWriter )。基本のItemWriterは、トランザクションとすべてのリソースを自分で管理することを期待しています。代わりに、RepositoryItemWriter(または適切な方)を使用してみてください。 EntityManagerを提供し、トランザクション内から書き込みが呼び出されるようにする必要がある場合があります(例:@Transactional 方法)。

5