简体   繁体   English

Spring 批处理 - 即使块引发一些异常,是否有办法提交数据?

[英]Spring Batch - Is there a way to commit data even if the chunk raise some exception?

I have a process that read from a queue, process and write into DB.我有一个从队列中读取、处理并写入数据库的进程。 Even if the process fails, I have to store in DB.即使过程失败,我也必须存储在数据库中。 But the Spring Batch steps are transactional and always rollback the changes.但是 Spring 批处理步骤是事务性的,并且总是回滚更改。 So, is there a way to commit data even if the chunk raise some exception?那么,即使块引发一些异常,有没有办法提交数据?

EDIT I:编辑我:

I tried with Tasklet but getting the same behaviour.我尝试使用 Tasklet,但得到了相同的行为。

Thanks in advance.提前致谢。

During configuring a step, you can use noRollback() to configure a list of exception that will not cause rollback.在配置步骤时,可以使用noRollback()来配置一个不会导致回滚的异常列表。 Any exceptions that are the subclass of configured exception will not rollback.作为已配置异常的子类的任何异常都不会回滚。 That means if you simply want to never rollback, set it as Exception which is the parent of all exceptions.这意味着如果您只是想永不回滚,请将其设置为Exception ,它是所有异常的父级。

An example can be found from the docs :可以从文档中找到一个示例:

@Bean
public Step step1() {
    return this.stepBuilderFactory.get("step1")
                .<String, String>chunk(2)
                .reader(itemReader())
                .writer(itemWriter())
                .faultTolerant()
                .noRollback(Exception.class)
                .build();
}

I tried to use noRollback() as Ken Chan suggested but did'nt work.我尝试按照 Ken Chan 的建议使用noRollback()但没有奏效。 Also try to put the specific exceptions, but it keeps doing rololback.还尝试放置特定的异常,但它一直在做回滚。

The conditional flow is at Step level no item level, so it doesn't help me.条件流在步骤级别没有项目级别,所以它对我没有帮助。 Also tried with Listeners but the documentation said:也尝试过 Listeners 但文档说:

This listener is designed to work around the lifecycle of an item. This means that each method should be called once within the lifecycle of an item and in fault tolerant scenarios, any transactional work that is done in one of these methods would be rolled back and not re-applied. Because of this, it is recommended to not perform any logic using this listener that participates in a transaction.

I solved my problem using Tasklet insted of chunked oriented solution and adding an @Transactional to the execute method of the Tasklet.我使用面向分块的解决方案的 Tasklet 解决了我的问题,并将 @Transactional 添加到 Tasklet 的执行方法中。

@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE, noRollbackFor = {
        ErrorInternoServidorException.class, SolicitudIncorrectaException.class,
        RegistroNoEncontradoException.class, SolicitudEventoObjetaException.class,
        SolicitudEventoValidaException.class, MimCargueSolicitudException.class, ConflictException.class,
        UnauthorizedException.class, ForbiddenException.class }) 
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

Spring Batch chunked oriented solution is wrapped in a Tasklet with his own transaction, so I tried to create a new one with my own rules. Spring 面向批量分块的解决方案被包装在一个带有他自己事务的 Tasklet 中,所以我尝试使用自己的规则创建一个新的。

Thanks to everyone for your replies.感谢大家的回复。 I learned a lot.我学到了很多。

One way you could write your JOB to commit all your data even when exceptions are raised in your processing is to use a SkipPolicy and write your data to the destination DB there.即使在处理过程中引发异常,您也可以编写 JOB 以提交所有数据的一种方法是使用 SkipPolicy 并将数据写入那里的目标数据库。

One of the main benefits of SkipPolicy is to log the data that caused and exception through the processing, and the logging part could even be inserting the record in a temporary Table in you DB. SkipPolicy 的主要好处之一是通过处理记录导致和异常的数据,并且记录部分甚至可以将记录插入数据库中的临时表中。

public class FileVerificationSkipper implements SkipPolicy {

    private static final int MAX_VALUES_TO_SKIP = 1000;
    private JdbcTemplate jdbcTemplate;

    public FileVerificationSkipper(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public boolean shouldSkip(Throwable exception, int skipCount) throws SkipLimitExceededException {
        if (exception instanceof FlatFileParseException && skipCount <= MAX_VALUES_TO_SKIP) {
            jdbcTemplate.update("INSERT INTO YourTable(column1, column2) VALUES(?,?)");
            return true;
        } else {
            return false;
        }
    }
}

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM