From b7aa99b906b21740784d860bff5ce5a164956c3f Mon Sep 17 00:00:00 2001 From: MrBird <852252810@qq.com> Date: Thu, 12 Mar 2020 11:25:15 +0800 Subject: [PATCH] =?UTF-8?q?Spring=20Batch=E5=BC=82=E5=B8=B8=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 72.spring-batch-exception/pom.xml | 46 +++++++++++++ .../SpringBatchExceptionApplication.java | 15 ++++ .../exception/MyJobExecutionException.java | 13 ++++ .../batch/job/DefaultExceptionJobDemo.java | 44 ++++++++++++ .../cc/mrbird/batch/job/RestartJobDemo.java | 51 ++++++++++++++ .../batch/job/RetryExceptionJobDemo.java | 69 +++++++++++++++++++ .../batch/job/SkipExceptionJobDemo.java | 68 ++++++++++++++++++ .../mrbird/batch/job/TransactionJobDemo.java | 58 ++++++++++++++++ .../mrbird/batch/listener/MySkipListener.java | 25 +++++++ .../src/main/resources/application.yml | 6 ++ 10 files changed, 395 insertions(+) create mode 100644 72.spring-batch-exception/pom.xml create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/SpringBatchExceptionApplication.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/exception/MyJobExecutionException.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/DefaultExceptionJobDemo.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RestartJobDemo.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RetryExceptionJobDemo.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/SkipExceptionJobDemo.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/TransactionJobDemo.java create mode 100644 72.spring-batch-exception/src/main/java/cc/mrbird/batch/listener/MySkipListener.java create mode 100644 72.spring-batch-exception/src/main/resources/application.yml diff --git a/72.spring-batch-exception/pom.xml b/72.spring-batch-exception/pom.xml new file mode 100644 index 0000000..e98e60f --- /dev/null +++ b/72.spring-batch-exception/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.5.RELEASE + + + cc.mrbird + spring-batch-exception + 0.0.1-SNAPSHOT + spring-batch-exception + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-batch + + + + mysql + mysql-connector-java + + + org.springframework.boot + spring-boot-starter-jdbc + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/SpringBatchExceptionApplication.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/SpringBatchExceptionApplication.java new file mode 100644 index 0000000..8a15c06 --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/SpringBatchExceptionApplication.java @@ -0,0 +1,15 @@ +package cc.mrbird.batch; + +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableBatchProcessing +public class SpringBatchExceptionApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBatchExceptionApplication.class, args); + } + +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/exception/MyJobExecutionException.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/exception/MyJobExecutionException.java new file mode 100644 index 0000000..a1d6166 --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/exception/MyJobExecutionException.java @@ -0,0 +1,13 @@ +package cc.mrbird.batch.exception; + +/** + * @author MrBird + */ +public class MyJobExecutionException extends Exception{ + + private static final long serialVersionUID = 7168487913507656106L; + + public MyJobExecutionException(String message) { + super(message); + } +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/DefaultExceptionJobDemo.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/DefaultExceptionJobDemo.java new file mode 100644 index 0000000..133ad1c --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/DefaultExceptionJobDemo.java @@ -0,0 +1,44 @@ +package cc.mrbird.batch.job; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +/** + * @author MrBird + */ +@Component +public class DefaultExceptionJobDemo { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; + + @Bean + public Job defaultExceptionJob() { + return jobBuilderFactory.get("defaultExceptionJob") + .start( + stepBuilderFactory.get("step") + .tasklet((stepContribution, chunkContext) -> { + // 获取执行上下文 + ExecutionContext executionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext(); + if (executionContext.containsKey("success")) { + System.out.println("任务执行成功"); + return RepeatStatus.FINISHED; + } else { + String errorMessage = "处理任务过程发生异常"; + System.out.println(errorMessage); + executionContext.put("success", true); + throw new RuntimeException(errorMessage); + } + + }).build() + ).build(); + } +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RestartJobDemo.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RestartJobDemo.java new file mode 100644 index 0000000..4768488 --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RestartJobDemo.java @@ -0,0 +1,51 @@ +package cc.mrbird.batch.job; + +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.item.support.ListItemReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.interceptor.DefaultTransactionAttribute; + +import java.util.ArrayList; +import java.util.stream.IntStream; + +/** + * @author MrBird + */ +@Component +public class RestartJobDemo { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; + + @Bean + public Job restartJob() { + return jobBuilderFactory.get("restartJob") + .start(step()) + .build(); + } + + private Step step() { + return stepBuilderFactory.get("step") + .chunk(2) + .reader(listItemReader()) + .writer(list -> list.forEach(System.out::println)) + // .allowStartIfComplete(true) + .startLimit(1) + .build(); + } + + private ListItemReader listItemReader() { + ArrayList datas = new ArrayList<>(); + IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); + return new ListItemReader<>(datas); + } +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RetryExceptionJobDemo.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RetryExceptionJobDemo.java new file mode 100644 index 0000000..8b73a86 --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RetryExceptionJobDemo.java @@ -0,0 +1,69 @@ +package cc.mrbird.batch.job; + +import cc.mrbird.batch.exception.MyJobExecutionException; +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.item.ItemProcessor; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.stream.IntStream; + +/** + * @author MrBird + */ +@Component +public class RetryExceptionJobDemo { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; + + @Bean + public Job retryExceptionJob() { + return jobBuilderFactory.get("retryExceptionJob") + .start(step()) + .build(); + } + + private Step step() { + return stepBuilderFactory.get("step") + .chunk(2) + .reader(listItemReader()) + .processor(myProcessor()) + .writer(list -> list.forEach(System.out::println)) + .faultTolerant() // 配置错误容忍 + .retry(MyJobExecutionException.class) // 配置重试的异常类型 + .retryLimit(3) // 重试3次,三次过后还是异常的话,则任务会结束, + // 异常的次数为reader,processor和writer中的总数,这里仅在processor里演示异常重试 + .build(); + } + + private ListItemReader listItemReader() { + ArrayList datas = new ArrayList<>(); + IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); + return new ListItemReader<>(datas); + } + + private ItemProcessor myProcessor() { + return new ItemProcessor() { + private int count; + @Override + public String process(String item) throws Exception { + System.out.println("当前处理的数据:" + item); + if (count >= 2) { + return item; + } else { + count++; + throw new MyJobExecutionException("任务处理出错"); + } + } + }; + } +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/SkipExceptionJobDemo.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/SkipExceptionJobDemo.java new file mode 100644 index 0000000..153b49d --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/SkipExceptionJobDemo.java @@ -0,0 +1,68 @@ +package cc.mrbird.batch.job; + +import cc.mrbird.batch.exception.MyJobExecutionException; +import cc.mrbird.batch.listener.MySkipListener; +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.item.ItemProcessor; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.stream.IntStream; + +/** + * @author MrBird + */ +@Component +public class SkipExceptionJobDemo { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; + @Autowired + private MySkipListener mySkipListener; + + @Bean + public Job skipExceptionJob() { + return jobBuilderFactory.get("skipExceptionJob") + .start(step()) + .build(); + } + + private Step step() { + return stepBuilderFactory.get("step") + .chunk(2) + .reader(listItemReader()) + .processor(myProcessor()) + .writer(list -> list.forEach(System.out::println)) + .faultTolerant() // 配置错误容忍 + .skip(MyJobExecutionException.class) // 配置跳过的异常类型 + .skipLimit(1) // 最多跳过1次,1次过后还是异常的话,则任务会结束, + // 异常的次数为reader,processor和writer中的总数,这里仅在processor里演示异常跳过 + .listener(mySkipListener) + .build(); + } + + private ListItemReader listItemReader() { + ArrayList datas = new ArrayList<>(); + IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); + return new ListItemReader<>(datas); + } + + private ItemProcessor myProcessor() { + return item -> { + System.out.println("当前处理的数据:" + item); + if ("2".equals(item)) { + throw new MyJobExecutionException("任务处理出错"); + } else { + return item; + } + }; + } +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/TransactionJobDemo.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/TransactionJobDemo.java new file mode 100644 index 0000000..161c30a --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/TransactionJobDemo.java @@ -0,0 +1,58 @@ +package cc.mrbird.batch.job; + +import cc.mrbird.batch.exception.MyJobExecutionException; +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.item.ItemProcessor; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.interceptor.DefaultTransactionAttribute; + +import java.util.ArrayList; +import java.util.stream.IntStream; + +/** + * @author MrBird + */ +@Component +public class TransactionJobDemo { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; + + @Bean + public Job transactionJob() { + return jobBuilderFactory.get("transactionJob") + .start(step()) + .build(); + } + + private Step step() { + DefaultTransactionAttribute attribute = new DefaultTransactionAttribute(); + attribute.setPropagationBehavior(Propagation.REQUIRED.value()); + attribute.setIsolationLevel(Isolation.DEFAULT.value()); + attribute.setTimeout(30); + + return stepBuilderFactory.get("step") + .chunk(2) + .reader(listItemReader()) + .writer(list -> list.forEach(System.out::println)) + .readerIsTransactionalQueue() + .transactionAttribute(attribute) + .build(); + } + + private ListItemReader listItemReader() { + ArrayList datas = new ArrayList<>(); + IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); + return new ListItemReader<>(datas); + } +} diff --git a/72.spring-batch-exception/src/main/java/cc/mrbird/batch/listener/MySkipListener.java b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/listener/MySkipListener.java new file mode 100644 index 0000000..f3370b9 --- /dev/null +++ b/72.spring-batch-exception/src/main/java/cc/mrbird/batch/listener/MySkipListener.java @@ -0,0 +1,25 @@ +package cc.mrbird.batch.listener; + +import org.springframework.batch.core.SkipListener; +import org.springframework.stereotype.Component; + +/** + * @author MrBird + */ +@Component +public class MySkipListener implements SkipListener { + @Override + public void onSkipInRead(Throwable t) { + System.out.println("在读取数据的时候遇到异常并跳过,异常:" + t.getMessage()); + } + + @Override + public void onSkipInWrite(String item, Throwable t) { + System.out.println("在输出数据的时候遇到异常并跳过,待输出数据:" + item + ",异常:" + t.getMessage()); + } + + @Override + public void onSkipInProcess(String item, Throwable t) { + System.out.println("在处理数据的时候遇到异常并跳过,待输出数据:" + item + ",异常:" + t.getMessage()); + } +} diff --git a/72.spring-batch-exception/src/main/resources/application.yml b/72.spring-batch-exception/src/main/resources/application.yml new file mode 100644 index 0000000..3bc8ce7 --- /dev/null +++ b/72.spring-batch-exception/src/main/resources/application.yml @@ -0,0 +1,6 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/springbatch + username: root + password: 123456