Spring 与 spring 批处理和 jpa 的启动集成
Spring boot integration with spring batch and jpa
我正在将 spring 引导项目与 spring 批处理和数据 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();
}
道class:
public interface PersonDao extends CrudRepository<Person,Integer> {
}
作家class:
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 的人对象,但下一行没有插入到数据库而没有错误。只是执行该行并继续循环。
我可能没注意到,但我没有看到您在哪里指定了您正在使用的数据库访问方法(JPA、Hibernate、JDBC 等)。我假设 JPA,但我认为您的 ItemWriter 需要扩展其中一个 DB-aware ItemWriters (RepositoryItemWriter,JpaItemWriter,JdbcBatchItemWriter, HibernateItemWriter)。基础 ItemWriter 希望您自己管理事务和所有资源。尝试改用 RepositoryItemWriter(或任何合适的)。您可能必须提供一个 EntityManager 并确保从事务中调用写入(例如某些 @Transactional
方法)。
此问题的解决方案可能比预期更接近。您是否只是尝试更改 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,如果是,它会使用找到的那个——而你的数据库事务正在通过一个无资源的事务)。
你也可以跳过这个:
@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
return new MapJobRepositoryFactoryBean(transactionManager).getObject();
}
并直接调用 bean(只是 'more sure' 正确的事务管理器与 Batch 一起使用):
@Bean
public JobRepository jobRepository() throws Exception {
return new MapJobRepositoryFactoryBean(resourcelessTransactionManager()).getObject();
}
测试时请告诉我,我希望这是主要问题:)
我正在将 spring 引导项目与 spring 批处理和数据 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();
}
道class:
public interface PersonDao extends CrudRepository<Person,Integer> {
}
作家class:
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 的人对象,但下一行没有插入到数据库而没有错误。只是执行该行并继续循环。
我可能没注意到,但我没有看到您在哪里指定了您正在使用的数据库访问方法(JPA、Hibernate、JDBC 等)。我假设 JPA,但我认为您的 ItemWriter 需要扩展其中一个 DB-aware ItemWriters (RepositoryItemWriter,JpaItemWriter,JdbcBatchItemWriter, HibernateItemWriter)。基础 ItemWriter 希望您自己管理事务和所有资源。尝试改用 RepositoryItemWriter(或任何合适的)。您可能必须提供一个 EntityManager 并确保从事务中调用写入(例如某些 @Transactional
方法)。
此问题的解决方案可能比预期更接近。您是否只是尝试更改 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,如果是,它会使用找到的那个——而你的数据库事务正在通过一个无资源的事务)。
你也可以跳过这个:
@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
return new MapJobRepositoryFactoryBean(transactionManager).getObject();
}
并直接调用 bean(只是 'more sure' 正确的事务管理器与 Batch 一起使用):
@Bean
public JobRepository jobRepository() throws Exception {
return new MapJobRepositoryFactoryBean(resourcelessTransactionManager()).getObject();
}
测试时请告诉我,我希望这是主要问题:)