【问题标题】:How do I prevent rollback when exception occurs in ItemWriter?ItemWriter发生异常时如何防止回滚?
【发布时间】:2020-01-07 15:36:10
【问题描述】:

我们的编写器旨在将记录写入关系数据库。 如果任何记录发生异常,Spring Batch 会对块中的每条记录执行回滚和重试写入操作。这会导致发生 SQL Duplicate Key 异常,因为块中先前处理的记录已成功写入数据库。

我们尝试使用 noRetry() 和 noRollback(),明确指定不应触发重试或回滚的异常列表。

根据 Spring Batch 在线文档 noRollback() 可用于在 ItemWriter 发生错误时防止回滚:https://docs.spring.io/spring-batch/4.1.x/reference/html/step.html#controllingRollback

然而,这与源代码中的 java doc 相矛盾,java doc 在写入过程中会忽略 FaultTolerantStepBuilder.noRollback(): https://docs.spring.io/spring-batch/4.1.x/api/index.html?org/springframework/batch/core/step/builder/FaultTolerantStepBuilder.html

这是我们的 Job 定义示例:

    @Bean("my-job")
    public Job job(Step step) {
        return jobBuilderFactory.get("my-job")
                .start(step)
                .build();
    }

    @Bean
    public Step step() {
        return stepBuilderFactory.get("skip-step")
            .<String, String>chunk(3)
            .reader(reader())
            .processor(myprocessor())
            .writer(this::write)
            .faultTolerant()
            .skipLimit(1)
            .skip(JobSkippableException.class)
            .noRollback(JobSkippableException.class)
            .noRetry(JobSkippableException.class)
            .processorNonTransactional()
            .build();
    }

    public ItemReader<String> reader() {
        return new ItemReader<String> () {

            @Override
            public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
                String s = randomUUID().toString(); 
                logger.debug("READ STRING {}", s);  
                return s;
            }
        };
    }

    public void write(List<? extends String> items) {
        for(String s : items) {
            logger.debug("WRITE STRING {}", s);
            throw new JobSkippableException("My skippable exception");
        }
    }

    public ItemProcessor <String, String> myprocessor() {
        return new ItemProcessor<String, String>() {

            @Override
            public String process(String item) throws Exception {
                logger.debug("PROCESS STRING {}", item);
                return item;
            }
        };
    }

我们的预期行为是 write 中发生的异常不会触发重试或回滚。这将防止重复调用数据库,因此不会导致 SQL Duplicate Key 异常。

【问题讨论】:

标签: spring-batch


【解决方案1】:

不是一个解决方案,但至少解释了为什么我在FaultTolerantChunkProcessor 的第 335-350 行中发现框架的行为不像您预期​​的那样:

                    try {
                        doWrite(outputs.getItems());
                    }
                    catch (Exception e) {
                        if (rollbackClassifier.classify(e)) {
                            throw e;
                        }
                        /*
                         * If the exception is marked as no-rollback, we need to
                         * override that, otherwise there's no way to write the
                         * rest of the chunk or to honour the skip listener
                         * contract.
                         */
                        throw new ForceRollbackForWriteSkipException(
                                "Force rollback on skippable exception so that skipped item can be located.", e);                   }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-13
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多