Spring boot Spring批处理在异常后保留写入记录

Spring boot Spring批处理在异常后保留写入记录,spring-boot,spring-batch,Spring Boot,Spring Batch,我有一个spring批处理作业,我必须检查所有文件行中的id是否相等,并且应该跳过包含不同id的行。我所做的是保存第一条记录,然后比较每一行的id,如果id不同,则抛出一个运行时异常,但出于某种原因,spring batch会一直工作,直到它得到“要排除”的行,然后通过在异常上写入所有记录来重复写入过程。 我的意思是: sms [ Id_Campaign=5598661] sms [ Id_Campaign=5598661] sms [ Id_Campaign=5598661] sms [ Id

我有一个spring批处理作业,我必须检查所有文件行中的id是否相等,并且应该跳过包含不同id的行。我所做的是保存第一条记录,然后比较每一行的id,如果id不同,则抛出一个运行时异常,但出于某种原因,spring batch会一直工作,直到它得到“要排除”的行,然后通过在异常上写入所有记录来重复写入过程。 我的意思是:

sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
2021-06-03 11:12:28.466 ERROR 41416 --- [   scheduling-1] tn.itserv.batch.SkipLinesListener        : An error occured while writing the input Force rollback on skippable exception so that skipped item can be located.
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=5598661]
sms [ Id_Campaign=7798661]
我的步骤:

    @Bean
    public Step loadFiles() throws IOException {
        return stepBuilderFactory
                .get("step1")
                .<FileModelIn, FileModelOut>chunk(100)
                .reader(multiResourceItemReader())
                .processor(batchProcessor())
                .writer(batchWriter())
                .faultTolerant()
                .skipPolicy(skipLinesListener())
                .noRetry(RuntimeException.class)
                .noRollback(RuntimeException.class)
                .listener(MyStepListner())
                .build();
    }
@Bean
公共步骤loadFiles()引发IOException{
返回stepBuilderFactory
.get(“步骤1”)
.chunk(100)
.reader(multiResourceItemReader())
.processor(batchProcessor())
.writer(batchWriter())
.容错()
.skipPolicy(skipLinesListener())
.noRetry(RuntimeException.class)
.noRollback(RuntimeException.class)
.listener(MyStepListner())
.build();
}
船长政策:

public class SkipLinesListener implements SkipPolicy {
    private static final int MAX_SKIP_COUNT = 10;
    private static final Logger logger = LoggerFactory.getLogger(SkipLinesListener.class);

    @Override
    public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
        if (t instanceof  RuntimeException && skipCount < MAX_SKIP_COUNT )
        { RuntimeException ex=(RuntimeException)t;
            logger.error("An error occured while writing the input "+ ex.getMessage());
            return true;
        }
        if (t instanceof FlatFileParseException && skipCount < MAX_SKIP_COUNT ) {
            FlatFileParseException ex = (FlatFileParseException) t;
           
         logger.error("An error occured while processing the "+ ex.getInput());
                return true;     
        }
    
    return false;
    
    }

}
公共类SkipLinesListener实现SkipPolicy{
私有静态最终整数最大跳过计数=10;
私有静态最终记录器Logger=LoggerFactory.getLogger(SkipLinesListener.class);
@凌驾
公共布尔值shouldSkip(Throwable t,int skipCount)抛出SkipLimitExceedeException{
if(运行时异常和skipCount的t实例<最大跳过计数)
{RuntimeException ex=(RuntimeException)t;
logger.error(“写入输入时出错”+ex.getMessage());
返回true;
}
if(FlatFileParseException和skipCount的t实例<最大跳过计数){
FlatFileParseException ex=(FlatFileParseException)t;
logger.error(“处理“+ex.getInput()”时出错);
返回true;
}
返回false;
}
}
我不知道为什么会有这种行为,我是不是错过了什么? 我正在itemwriter类中引发异常

@Override
public void write(List<? extends FileModelOut> items) throws Exception {
        List<FCCampaignModel> campaigns=new ArrayList<FCCampaignModel>();   
        List<sms> smsList=new ArrayList<>();
        FCCampaignModel firstLine=cmsDaoProxy.addCampaign(items.get(0).getFcCampaignModel());
        
        for (FileModelOut fileContent : items) {
         if (fileContent.getFcCampaignModel().getId_Campaign().equals(firstLine.getId_Campaign()))
            {
             
            smsRepository.save(fileContent.getSms());
            }
         else throw new RuntimeException("different id campaign detected : "+fileContent.getFcCampaignModel().getId_Campaign());
         
        }
@覆盖

public void write(List您的异常被声明为可跳过的异常,因此当它从项目编写器中抛出时,Spring Batch将逐项扫描区块,即逐个重新处理项目,每个项目在其自己的事务中


这是因为项目是分块编写的(即批量模式),并且如果在大容量写入操作期间发生异常,Spring Batch无法知道是哪个项导致了问题,因此它将逐个重试。您可以在示例模块中找到一个示例:。

您的异常被声明为可跳过的异常,因此当它从项目编写器中抛出时,Spring Batch将逐项扫描块,ie逐个重新处理项目,每个项目在其自己的事务中


这是因为项目是分块编写的(即批量模式),并且如果在大容量写入操作期间发生异常,Spring Batch无法知道是哪个项导致了问题,因此它将逐个重试。您可以在示例模块中找到一个示例:。

请将代码附加到引发RuntimeException的位置。在上面添加一些日志以确定错误的模式。行为是什么你在期待什么?我可以看到你使用了跳过逻辑。我编辑了它并添加了抛出异常的部分。请附上抛出RuntimeException的代码。在上面添加一些日志以确定错误模式。你在期待什么行为?我可以看到你使用了跳过逻辑。我编辑了它并添加了t我抛出异常的部分我理解的是,这是正常的behvior,那么有没有办法防止逐个重新处理项目,并在异常后继续写入区块?因为如果项目逐个处理
if(fileContent.getfccampatingmodel().getId_Campaign().equals(firstLine.getId_Campaign())将始终为真
否,有一个开放的功能请求:。但您的情况确实很具体:
我必须检查所有文件行中的id是否相等,并应跳过包含不同id的行
:您在writer中执行的操作应在项目处理器中完成。筛选数据(您似乎称之为skip)是项目处理程序的典型用例。您没有将实际问题与输入数据示例分享,但您的跳过策略似乎不适合该用例。因此,我应该将id检查部分移到有意义的处理程序。非常感谢您的帮助。在这种情况下,请接受答案:。谢谢。i u据了解,这是正常的behvior,那么有没有办法防止逐个重新处理项目,并在异常后继续写入区块?因为如果项目逐个处理
if(fileContent.getfccampaigmodel().getId_Campaign().equals(firstLine.getId_Campaign())将始终为真
否,有一个开放的功能请求:。但您的情况确实很具体:
我必须检查所有文件行中的id是否相等,并应跳过包含不同id的行
:您在writer中执行的操作应在项目处理器中完成。筛选数据(您似乎称之为skip)是项目处理器的典型用例。您没有将实际问题与输入数据示例分享,但您的跳过策略似乎不适合该用例。因此,我应该将id检查部分移动到有意义的处理器。非常感谢您的帮助。在这种情况下,请接受回答:。谢谢。