简体   繁体   中英

Spring Batch Transactions in StepExecutionListener

I have a spring batch job that reads data from a web service, does some enriching in a processor and then saves to DB. If someone runs the same job twice for same set of param I want to delete the old data in db and then re-write as part of this job.

I have written the delete logic in StepExecutionListener Before Step Method.

How can I make my step transactional so that if there is an error in the job the delete operation is rolledback?

this.stepBuilderFactory.get("xStep")
.<Item,Item>chunk(1000)
.reader(xReader)
.processor(xProcessor)
.writer(xWriter)
.listener(xStepExecutionListenerForDelete)
.build()

How can I make my step transactional so that if there is an error in the job the delete operation is rolledback?

You can write the delete logic as part of the item writer which is called inside the transaction driven by Spring Batch. If the transaction is rolled back for any reason, your delete operation will be rolled back. Note that an item writer is not only used for inserting data, but can be used to update data and delete it as well ( MongoItemWriter#setDelete is an example).

Job Parameters

The job won't begin if there is already an instance with the same "identifying" job parameters.

The job will shutdown with the following exception: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException

You could create a job parameter that is a randomly generated value, or perhaps a date. In your listener, you could verify the job parameters of the previous job instance excluding your "unique" job parameter.

Transactional Listener

Add the @Transactional annotation to the listener to have it wrapped in a transaction.

Example

@Transactional
public class DataErasureListener implements StepExecutionListener {

    @Autowired
    JobExplorer jobExplorer;

    @Override
    public void beforeStep(StepExecution stepExecution) {

        String jobName = stepExecution.getJobExecution().getJobInstance().getJobName();
        Map<String, JobParameter> currentJobParameters = stepExecution.getJobParameters().getParameters();

        int jobInstanceCount = jobExplorer.getJobInstanceCount(jobName);

        if (jobInstanceCount == 1) {
            //No prior run
            return;
        }

        //The list of JobInstances are in descending order of creation. Grab the 2nd one.
        JobInstance priorJobInstance = jobExplorer.getJobInstances(jobName, 0, jobInstanceCount).get(1);
        JobExecution priorJobExecution= jobExplorer.getLastJobExecution(priorJobInstance);
        Map<String, JobParameter> priorJobParameters = priorJobExecution.getJobParameters().getParameters();

        //Compare prior job parameters excluding "unique" job parameters
        currentJobParameters.remove("unique");
        priorJobParameters.remove("unique");

        if (currentJobParameters.equals(priorJobParameters)) {
            //Delete old data
        }
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return stepExecution.getExitStatus();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM