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