<Spring Batch>为什么使ItemReader线程安全导致我们失去可重启性?

我有一个从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();
  }
}

回答(2)

2 years ago

当使用具有多线程的ItemReader时,缺乏可重启性与读取本身无关 . 它是关于保存更新方法中发生的阅读器状态 . 问题是read()调用之间需要协调 - 提供数据的方法和update() - 持久化状态的方法 . 当您使用多个线程时,阅读器的内部状态(以及update()调用)可能会也可能不会反映已完成的工作 . 以使用块大小为5并在多个线程上运行的FlatFileItemReader为例 . 你可以让thread1读取5个项目(更新时间),但是线程2可以读取额外的3个 . 这意味着更新调用将保存已读取的8个项目 . 如果线程2上的块失败,则状态将不正确,并且重新启动将错过已读取的三个项目 .

这并不是说编写线程安全的ItemReader是不可能的 . 但是,正如您上面的示例所示,如果delegate是有状态的ItemReader(也实现了ItemStream),那么调用update时状态将不会被正确保持(事实上,上面的示例甚至没有采用阶段性读者的ItemStream方面考虑到) .

2 years ago

如果你想让你的作业重新启动,并行执行项目,你可以自己保存项目,读者阅读以及该项目的状态 .