3

我有一个从数据库读取的多线程批处理作业,我担心不同的线程会重新读取记录,因为 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();
  }
}
4

2 回答 2

5

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

这并不是说不可能编写线程安全的 ItemReader。但是,正如您上面的示例所示,如果委托是有状态的 ItemReader(也实现了 ItemStream),则状态将不会通过调用 update 正确持久化(实际上,您上面的示例甚至没有采用分阶段阅读器的 ItemStream 方面考虑)。

于 2013-11-15T13:45:05.923 回答
0

如果你想让你的工作可以重新启动,并行执行项目,你可以保存项目,读者自己读取这个项目的状态。

于 2014-02-27T11:56:16.853 回答