我有一个从DB读取的多线程批处理作业,我担心不同的线程重新读取记录,因为ItemReader在Spring批处理中不是线程安全的。我浏览了SpringBatch FAQ部分,其中说明了
您可以同步read()方法(例如,通过将其包装在执行同步的委托器中)。请记住,您将失去可重启性,因此最佳做法是将步骤标记为不可重新启动,并且为了安全(和有效),您还可以在阅读器上设置saveState = false。
我想知道为什么在这种情况下我会失去重新启动性?可重启性与同步我的读取操作有什么关系?它总是可以再试一次,对吗? 此外,这段代码是否足以同步读者?
public SynchronizedItemReader<T> implements ItemReader<T> {
private final ItemReader<T> delegate;
public SynchronizedItemReader(ItemReader<T> delegate) {
this.delegate = delegate;
}
public synchronized T read () {
return delegate.read();
}
}
答案 0 :(得分:4)
当使用具有多线程的ItemReader时,缺乏可重启性与读取本身无关。它是关于保存更新方法中发生的阅读器状态。问题是read()调用之间需要协调 - 提供数据的方法和update() - 持久化状态的方法。当您使用多个线程时,阅读器的内部状态(以及update()调用)可能会也可能不会反映已完成的工作。以使用块大小为5并在多个线程上运行的FlatFileItemReader为例。你可以让thread1读取5个项目(更新时间),但是线程2可以读取额外的3个。这意味着更新调用将保存已读取的8个项目。如果线程2上的块失败,则状态将不正确,重启将错过已读取的三个项目。
这并不是说编写线程安全的ItemReader是不可能的。但是,正如您上面的示例所示,如果delegate是有状态的ItemReader(也实现了ItemStream),则调用update时状态将不会被正确保持(事实上,上面的示例甚至没有采用阶段性读者的ItemStream方面考虑到了。)
答案 1 :(得分:0)
如果你想让你的作业重新启动,并行执行项目,你可以自己保存项目,读者阅读以及这个项目的状态。