Spring Boot + Spring JPA + Spring Batch无法以一致的方式保存数据

时间:2017-10-04 17:53:26

标签: java spring-boot spring-data-jpa spring-batch

我在批处理应用程序中使用Sprig-Boot + Spring-JPA + Spring-Batch进行数据库CRUD操作。有几次我发现应用程序运行正常,没有任何异常,但数据没有插入数据库。为了解决这种行为,尝试了以下与问题完全无关的解决方法,但令人惊讶的是它们间歇性地工作。

  • 在服务层中的save()调用之后添加了记录器。
  • 在服务层中的save()调用之后添加了flush()。
  • 在服务层中来回更改REQUIRED和REQUIRED_NEW之间的传播级别。

以上的变通方法工作了几天,但我再次遇到这个间歇性的问题。我也尝试过EntityManager(而不是Spring-JPA),但它的行为方式也相同。

的pom.xml

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.2.RELEASE</version>
</parent>
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc7</artifactId>
        <version>12.1.0.1</version>
</dependency>

ServiceImpl.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
public class ServiceImpl {

    @Autowired
    private RepositoryImpl repositoryImpl;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    /* @Transactional(propagation = Propagation.REQUIRES_NEW) */
    public void save(List<MyCustomObject> objects) {
        repositoryImpl.save(objects);
        /* log.info("Added records in DB"); */ 
        /* repositoryImpl.flush(); */
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    /* @Transactional(propagation = Propagation.REQUIRES_NEW) */
    public void save(MyCustomObject object) {
        repositoryImpl.save(object);
        /* log.info("Added records in DB"); */
        /* repositoryImpl.flush(); */   
    }
}

RepositoryImpl.java

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional(readOnly=true)
public interface RepositoryImpl extends PagingAndSortingRepository<MyCustomObject, String> { 

    List<MyCustomObject> findByFirstName(String firstName);

    List<MyCustomObject> findByCity(String city);
}

MyCustomObject.java

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.SequenceGenerator;
    import javax.persistence.Table;

    @Entity(name = "myCustomObject")
    @Table(name = "MY_CUSTOM_OBJECT")
    public class MyCustomObject implements Serializable {

        private static final long serialVersionUID = 5187508219838537687L;

        @Id
        @SequenceGenerator(name = "MY_CUSTOM_OBJECT_SEQ_ID", sequenceName = "MY_CUSTOM_OBJECT_SEQ_ID", allocationSize = 1)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_CUSTOM_OBJECT_SEQ_ID")
        @Column(name="MY_CUSTOM_OBJECT_ID")
        private Long myCustomObjectId;

        @Column(name="FIRST_NAME")
        private String firstName;

        @Column(name="LAST_NAME")
        private String lastName;

        @Column(name="CITY")
        private String city;
}

MyCustomJobConfiguration.java

import java.util.Collection;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.step.tasklet.TaskletStep;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyCustomJobConfiguration {

    @Bean
    public Job myCustomJob(JobBuilderFactory jobs, Step webIdStoreStep, MyCustomJobBatchListener myCustomJobBatchListener) {

        return jobs.get("myCustomJob").listener(myCustomJobBatchListener)
                                      .start(myCustomPersistStep)
                                      .build();
    }

    @Bean
    public Step myCustomPersistStep(StepBuilderFactory stepBuilderFactory, MyCustomPersistTasklet myCustomPersistTasklet) {

           TaskletStep step = stepBuilderFactory.get("myCustomPersistStep")
                                                .tasklet(myCustomPersistTasklet)
                                                .build();
           step.setAllowStartIfComplete(Boolean.TRUE);
           return step;
       }
}

MyCustomPersistTasklet.java

@Component
@Slf4j
public class MyCustomPersistTasklet implements Tasklet {

    @Autowired
    private ServiceImpl serviceImpl;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        List<MyCustomObject> objects = getMyCustomObjects();
        serviceImpl.save(objects);
        return RepeatStatus.FINISHED;
    }
}   

MyCustomDto.java

import lombok.Data;
@Data
public class MyCustomDto {

    private String firstName;

    private String lastName;

    private String city;
}

MyCustomProcessDto.java

import lombok.Data;
@Data
public class MyCustomProcessDto {

    private MyCustomDto myCustomDto;

    private OtherCustomInfoDto otherCustomInfoDto;
}

CustomSpringBatchJobConfigurer.java

import javax.sql.DataSource;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@EnableBatchProcessing
@Import({ ServiceConfiguration.class })
public class CustomSpringBatchJobConfigurer {

    @Bean
    public BatchConfigurer configurer(
            @Qualifier("dataSource") DataSource dataSource) {
        return new DefaultBatchConfigurer(dataSource);
    }

    @Bean
    public JobRepository getJobRepository(
            @Qualifier("dataSource") DataSource dataSource,
            @Qualifier("transactionManager") PlatformTransactionManager transactionManager)
            throws Exception {
        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTransactionManager(transactionManager);
        factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
        factory.setValidateTransactionState(false);
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    @Bean
    public SyncTaskExecutor taskExecutor() {
        return new SyncTaskExecutor();
    }

    @Bean
    public JobRegistry jobRegistry() {
        return new MapJobRegistry();
    }

    @Bean
    public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
        JobRegistryBeanPostProcessor bean = new JobRegistryBeanPostProcessor();
        bean.setJobRegistry(jobRegistry());
        return bean;
    }
}

我尝试以最佳方式格式化代码。如果需要更多信息,很乐意分享。在此先感谢。

0 个答案:

没有答案