单个事务中的Spring批处理tasklet

时间:2016-08-05 14:50:39

标签: spring-batch

我使用FlatFileItemReader创建了一个Spring批处理作业,它从分隔文件中读取数据,然后使用JdbcBatchItemWriter写入DB。我的setp配置如下所示。

<batch:step id="step1">
        <batch:tasklet>
            <batch:chunk reader="fileReader" 
                writer="dbWriter" commit-interval="100">
            </batch:chunk>
        </batch:tasklet>
</batch:step>

上面的配置为每100个开放单独的事务,因此如果在完成tasklet(步骤1)之前发生故障,那么我无法恢复先前提交的行。有没有办法在单个事务中运行整个tasklet?。

P.S:我使用MapJobRepositoryFactoryBean作为工作存储库,不想在数据库中创建元表以重新启动。

2 个答案:

答案 0 :(得分:0)

在Spring批处理中,作业一次只能有一个事务。

请注意下图,因为我们可以看到事务在步骤开始时打开,并在步骤结束时提交。

Spring Batch transaction management

Image Source

事实上,使用spring批次的一个主要优点是我们作为开发人员不必担心事务管理。即使出现故障,它也会自动回滚整个未提交的事务。

答案 1 :(得分:0)

(自从我上次使用Spring Batch以来已经有一段时间了,我希望我的理解仍然有效:P)您可以简单地创建一个简单的tasklet,而不是使用面向chuck的tasklet。默认情况下,一个简单的tasklet将在单个事务中运行。鉴于你已经构建了读者和编写器,你可以编写一个模拟面向chuck的步骤的tasklet(只是伪代码向你展示这个想法):

public class ReaderWriterTasklet<T> implements Tasklet {
    private ItemReader<T> reader;
    private ItemWriter<T> writer;
    // and corresponding setters

    public RepeatStatus execute(StepContribution contribution,
                     ChunkContext chunkContext) {
        List<T> chunk = new LinkedList<T>();
        while (true) {
            T item = reader.read();
            if (item == null) {
                break;
            } else {
                chunk.add(item);
            }
        }
        writer.write(chunk);
        return RepeatStatus.FINISHED;
    }
}

(我相信你应该已经知道如何定义运行tasklet的步骤了吗?我会跳过那个)

另一种脏方法是继续使用chunk,并将commit-interval设置为Integer.MAX_VALUE。通过这样做,面向块的步骤将继续从读取器获取项目直到它到达结束,并在一个大块中写入编写器,这一切都发生在一个事务中。