Spring Boot与Spring Batch和JPA的集成

17

我正在将一个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();
}

Dao类:

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的人物对象,但在下一行没有插入到数据库中也没有出现错误,只是执行该行并继续循环。


我遇到了类似的问题。这个问题有任何更新吗? - balteo
2
我对Spring Batch一无所知,但使用ResourceLessTransactionManager和MapJobRepositoryFactory被记录为“用于内存持久性和测试目的”(http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#inMemoryRepository)。尝试使用JPA事务管理器和真实的JobRepository。 - JB Nizet
你说得对,我应该更仔细地阅读这篇文章。我的问题因此不同。我在这里包含它:https://dev59.com/w5jga4cB1Zd3GeqPPMno - balteo
2个回答

7
这个问题的解决方法可能比预期更接近。你是否尝试过更改transactionManager bean的名称?使用不同的名称,Spring Data JPA不会默认使用它。
我重现了你的问题,然后我简单地切换了这个:
@Bean
public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
}

转换为:

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

在我看来,这解决了问题。请记住,在Spring Data JPA中,“transactionManager”是事务管理器的默认bean名称(至少就我而言,Spring Boot自动配置它,除非它找到了具有该名称的Bean,如果找到,它将使用找到的那一个-并且您的数据库事务正在通过Resourceless one进行)。

您还可以跳过此步骤:

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

并直接调用Bean(只是为了“更加确定”批处理中使用适当的事务管理器):

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

测试完后请告诉我,希望这是主要问题 :)


5

我可能错过了,但我没有看到您指定使用什么数据库访问方法(JPA、Hibernate、JDBC等)。我假设您使用的是JPA,但我认为您的ItemWriter需要扩展一个DB-aware ItemWriters (RepositoryItemWriter,JpaItemWriter,JdbcBatchItemWriter, HibernateItemWriter)。基本的ItemWriter希望您自己管理事务和所有资源。尝试使用RepositoryItemWriter(或适当的其他ItemWriters)代替。您可能需要提供一个EntityManager,并确保write方法在Transaction中被调用(例如一些@Transactional方法)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接