我在批处理应用程序中使用Sprig-Boot + Spring-JPA + Spring-Batch进行数据库CRUD操作。有几次我发现应用程序运行正常,没有任何异常,但数据没有插入数据库。为了解决这种行为,尝试了以下与问题完全无关的解决方法,但令人惊讶的是它们间歇性地工作。
以上的变通方法工作了几天,但我再次遇到这个间歇性的问题。我也尝试过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;
}
}
我尝试以最佳方式格式化代码。如果需要更多信息,很乐意分享。在此先感谢。