Spring Batch 之 skip讲解(九)

      前面的文章跟大家一起讨论了Spring Batch的概念,处理流程,以及SpringBatch处理文件、DB的一些简单实例。接下来的讨论,主要是关于Spring Batch的一些高级应用处理和实际开发中需要注意的一些问题。

      今天主要和大家讨论SpringBatch关于skip容错机制的一些处理。

      一、skip的介绍

      在实际的项目开发中,我们常常要将几十万甚至上百万的数据从文件导入到DB中,如果其中某条数据导入时发生例外,我们并不想整个Job以失败而结束,而是希望能将错误的数据经过处理后保存起来,其余正确的数据继续做导入处理。如果遇到这样的场景,SpringBatch的skip机制就可以派上用场了。顾名思义,skip的作用就是跳过某些数据(例如错误数据)。 

      二、配置skip信息

      配置skip的示例代码如下:

 1 <job id="csvJob">
2 <step id="csvStep">
3 <tasklet transaction-manager="transactionManager">
4 <chunk reader="itemReaders" writer="itemWriter" processor="itemProcessor"
5 commit-interval="1" skip-limit="1000">
6 <skippable-exception-classes>
7 <include class="org.springframework.batch.item.file.FlatFileParseException" />
8 </skippable-exception-classes>
9 </chunk>
10 </tasklet>
11 </step>
12 </job>

      代码第5行chunk的skip-limit属性是指允许跳过记录的行数,6-8行是指允许发生的例外,也就是说在发生FlatFileParseException(及其子类)的时候,job是不会被终止的,而是跳过当前的记录,去执行下面那条记录。 上面的代码也会有另外一个问题,就是发生FlatFileParseException以外例外的时候,Job也会失败。这也满足不了我们上面说的那种场景,当然,6-8行还有另外一种配置方式,如下:

1 <skippable-exception-classes>
2   <include class="java.lang.Exception"/>
3 <exclude class="java.io.FileNotFoundException"/>
4 </skippable-exception-classes>

      include是允许跳过的错,exclude是不允许跳过的错。如果像上诉代码那样配置的话,所有Exception及其子类(FileNotFoundException除外)发生时,Job都不会被终止;但是当FileNotFoundException发生时,虽然它也是Exception的子类,但Job会被终止,因为FileNotFoundException属于exclude属性的class。

      三、skip深入讲解

      是谁在决定当前的记录跳过与否呢?其实,当Reader、Processor和Writer抛出例外的时候,SpringBatch会调用skip机制,来判断当前例外发生时,正在被处理的记录是否被跳过。当在上面的代码中配置skippable-exception-classes属性的时候,SpringBatch会默认的调用LimitCheckingItemSkipPolicy类。如果简单的配置skip-limit和skippable-exception-classes不能满足需求时,也可以定义自己的skip策略。代码如下:

 1 package com.wanggc.springbatch.sample;
2
3 import org.springframework.batch.core.step.skip.SkipLimitExceededException;
4 import org.springframework.batch.core.step.skip.SkipPolicy;
5
6 /**
7 * 自定义Skip策略类。
8 * @author Wanggc
9 */
10 public class MySkipPolicy implements SkipPolicy {
11
12 @Override
13 public boolean shouldSkip(Throwable t, int skipCount)
14 throws SkipLimitExceededException {
15 // TODO Auto-generated method stub
16 return false;
17 }
18 }

      如示例代码所示,要实现SkipPolicy接口,在shouldSkip方法中定义自己的skip策略。返回false时,说明当前例外不能被跳过,否则可以被跳过。当然,定义了自己的skip策略还不够,还要告诉框架要使用自己定义的skip策略,而不是框架默认的。这就需要添加chunk的另外一个属性skip-policy。代码如下:

 1 <job id="csvJob">
2 <step id="csvStep">
3 <tasklet transaction-manager="transactionManager">
4 <chunk reader="itemReaders" writer="itemWriter" processor="itemProcessor"
5 commit-interval="1" skip-limit="1000" skip-policy="mySkipPolicy">
6 <skippable-exception-classes>
7 <include
8 class="org.springframework.batch.item.file.FlatFileParseException" />
9 </skippable-exception-classes>
10 </chunk>
11 </tasklet>
12 </step>
13 </job>
14 <bean:bean id="mySkipPolicy" class="com.wanggc.springbatch.sample.MySkipPolicy"/>

      添加了skip-policy属性后,skip-limit和skippable-exception-classes默认策略将不再起作用。当然,可以将其删除,示例中属于垃圾代码。

      当Reader、Processor和Writer抛出例外的时候,SpringBatch处理skip策略的方式是不同的。当Reader发生可以被skip的例外时,SpringBatch会接着去读下面一条记录,并不会回滚事务。当Processor发生可以被skip的例外时,SpringBatch会回滚当前chunk的事务,并将除了引发例外以外的数据传给Writer。当Writer发生可以被skip的例外的时,SpringBatch首先回滚事务,因为传给Writer的是一个list,所以Writer不知道是list中那条记录造成了例外的发生。Writer会将list拆开,一条条的处理,正确的数据提交,错误的数据回滚。

      对SpringBatch的skip机制的讨论就到这里了,接下来会讨论其他一些高级属性。

 

你可能感兴趣的:(spring)