spring batch的skip逻辑是如何实现的

本文介绍了Spring Batch的skip逻辑,包括skip在处理过程中的作用,如何配置skip限制,以及skip逻辑的实现原理,强调了skip是基于事务支持的,并讨论了在read和write过程中如何处理异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

所谓skip是指的在spring batch的一个step当中,可以通过skip相关的方法提供一些容错机制。

在许多情况下,在spring batch在执行job过程中遇到的错误不应导致一个step的失败,而是可以选择跳过-skip。 至于怎么决定是否跳过某一个exception则通常是必须由了解数据本身及其含义的人来决定。 例如,财务数据往往是无法skip的,因为财务数据的背后是资金的转移,需要保证完全准确。然而某一些操作可能是可以允许跳过的,例如如果由于格式不正确或缺少必要信息而未加载某些无关紧要的内容,则并不会出现问题。

skip在springbatch中的用法

下面的代码是使用java config的一个step配置的例子

@Bean
public Step step1() {
        return this.stepBuilderFactory.get("step1")
                                .<String, String>chunk(10)
                                .reader(flatFileItemReader())
                                .writer(itemWriter())
                                .faultTolerant()
                                .skipLimit(10)
                                .skip(FlatFileParseException.class)
                                .build();
}

在上面的代码中,使用了FlatFileItemReader。 在整个step的执行过程当中任何时候抛出FlatFileParseException,则跳过该次异常并计算总跳过次数是否超过了配置的skiplimit上限10. 在step的执行过程当中,read,process和write中出的错误都会计数,且与skip limit进行比较。 当异常次数达到skiplimit限制的次数之后,若再次出现该异常则会导致step失败。 换句话说,在上面的这个例子当中,第十一次遇到FlatFileParseExcetion时才会触发异常导致失败,而不是第十次。

前面示例的一个问题是除了FlatFileParseException之外,任何其他异常只要遇到一次都会导致Job失败。 在某些情况下,这可能是正确的行为。 但是,在其他情况下,更有用的场景可能是识别哪些异常应该导致step失败,而跳过其他所有异常,下面的示例实现了这样的功能:

@Bean
public Step step1() {
        return this.stepBuilderFactory.get("step1")
                                .<String, String>chunk(10)
                                .reader(flatFileItemReader())
                                .writer(itemWriter())
                                .faultTolerant()
                                .skipLimit(10)
                                .skip(Exception.class)
                                .noSkip(FileNotFoundException.class)
                                .build();
}

上面的代码将java.lang.Exception标识为可跳过的异常类,则意味着对于这个step来说所有类型的异常都是可跳过的。 但是,它同时通过noskip方法'排除'了java.io.FileNotFoundException,此时这个step将可跳过的异常类list细化为除了FileNotFoundException之外的所有异常。 那么遇到任何被排除了的的异常类都会导致step失败(也就是说,它们不会被跳过).

对于遇到的任何异常,是否可跳过由该异常类的类层次结构中最近的父类确定。 任何未分类的异常都被视为“会导致失败”。

同时,skip和noSkip调用的顺序对结果没有影响。

另外,按照上述代码我们是使用的默认的skip策略,我们可以自己实现自己的skip策略并且配置在step当中,实现skip策略仅需要实现SkipPolicy接口即可.

skip逻辑的实现原理

skip在spring的一个step中的工作原理大致如下图所示:

上图展示的是在process过程中出现异常的处理流程。从上图我们不难发现,skip的实现是基于事务的支持的,在step当中若遇到一个可被跳过的exception,则当前的transaction会回滚. spring batch会把reader读取到的item缓存下来,因此,当某一天记录出错导致skip的时候,则这条记录就会从cache当中被删除掉。

紧接着,spring batch会重新开启一个事务,并且这个事务处理的数据是去除掉skip记录的cache数据。如果配置了SkipListener,则在提交一个chunk之前,SkipListener的onSkipInProcess方法会被调用。

若配置了跳过的次数限制,则在每一次遇到skippable 的exception时,计数器都会加一,当达到限制时step就会fail。

但是在read或者write过程中出现异常则情况会更加复杂。

以writer为例,writer对于所有的chunk里的数据只会调用一次。因此spring无法知道到底是chunk里的哪个item导致了异常。要找出来是哪一条记录出错,唯一方法是将chunk分成只包含一条记录的小块。如下图所示:

在把chunk拆分开之后会再次进入循环,在图中用红色表示。对于reader当中读取到的缓存的数据中的每个item,都将开启一个自己的事务。在开启事务之后,依然先由ItemProcessor处理,然后再由ItemWriter写入。 如果在这个过程当中没有错误,则提交这个只包含一条记录的迷你chunk,并且循环迭代继续下一个item。

在上诉过程当中应当至少有一个可跳过的异常,当遇到可跳过异常时,事务将被回滚并且该条数据被标记为跳过的项。当所有的数据遍历处理完之后,我们继续正常的chunk处理流程。

此外,我们通过将chunk上的属性transactional设置为false(默认为true),将它定义为非事务性的。 如果这样做,Spring Batch会缓存已处理的项目,并且在写入失败时不重新执行ItemProcessor。 如果在process阶段没有与事务资源的交互,则可以执这样设置,否则在写入失败时springbatch就不会重新执行process逻辑。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值