使用弹簧批处理读取一个记录/项目并写入多个记录/项目

Posted

技术标签:

【中文标题】使用弹簧批处理读取一个记录/项目并写入多个记录/项目【英文标题】:Read one record/item and write multiple records/items using spring batch 【发布时间】:2011-12-15 05:14:37 【问题描述】:

我进行了一些搜索,但找不到任何示例/示例。

我需要读取一个表(输入)中的地理坐标,并对其进行处理以生成与坐标相关联的 POI。因此,一个地理坐标将导致一个或多个 POI 需要插入到另一个表(输出)中。

我目前正在使用 JdbcCursorItemReader 和 JdbcBatchItemWriter 来读取一项/记录并写入一项/记录。还有一个 ItemProcessor 可以为给定的地理坐标生成 POI。

自定义 JdbcBatchItemWriter 是否可以帮助我实现这一目标?

有什么想法吗? TIA。

【问题讨论】:

【参考方案1】:

我通过扩展 Writer 类(在我的例子中为 HibernateItemWriter)来做到这一点。我看到一个答案描述了如何使用“分离器”。如果有人有一个工作示例,说明在使用 spring-boot-starter-parent 的环境中如何工作,我很乐意看到它。对于我正在做的事情(从单个记录创建列表),如果 Spring 提供了一个处理列表列表的写入方法,那将会容易得多。

这是我如何扩展 Writer 以处理读取/处理的每​​一行的多次写入:Spring-Batch Multi-line record Item Writer with variable number of lines per record

【讨论】:

【参考方案2】:

您真正要寻找的是Splitter 模式:

这是Spring Integration中的定义方式:

Splitter 是一种 Message Endpoint,其职责是从其输入通道接受一条消息,将该消息拆分为多个消息,然后将每个消息发送到其输出通道。这通常用于将“复合”有效负载对象划分为一组包含细分有效负载的消息。

配置极其简单:

<channel id="inputChannel"/>

<splitter id="splitter" 
  ref="splitterBean" 
  method="split" 
  input-channel="inputChannel" 
  output-channel="outputChannel" />

<channel id="outputChannel"/>

<beans:bean id="splitterBean" class="sample.PojoSplitter"/>

或者你可以使用注解:

@Splitter
List<LineItem> extractItems(Order order) 
    return order.getItems()

如果感觉更简单,您当然可以编写自己的JdbcBatchItemWriter。然而,Spring Integration 已经为您做到了。

您可以使用Spring Integration JDBC Support => jdbc:inbound-channel-adapter / jdbc:outbound-channel-adapter 和上面的拆分器来实现您想要的和......简单。

【讨论】:

只是好奇,restart 是否也适用于 spring 集成?或者换句话说,spring 集成只是一个薄的可插拔模块吗? 你绝对可以做 rerun vs restart (这是一个哲学讨论,因为 rerun 更干净:)。但是,如果您想在 Spring Batch(瘦可插拔模块)中使用它,您可以。尽管对于@user977505 的情况,单独使用 Spring Integration 和可能的一些 SB 组件(或没有)就可以了。 感谢您的回复。我会试一试并更新线程。 有人做过吗?或者有代码的链接?我查看了一些 spring 集成文档,但除了提到它是可能的之外找不到太多 @Splitter 注释去哪儿了?【参考方案3】:

如果您只想将项目分散到不同的作者(读取重复输出),您可以使用现有的CompositeItemWriter

但我不确定您的处理器是否会产生不同的项目类型,或者您是否想将一种复杂项目类型的内容传播给多个作者,对于这些情况,您可以使用稍微更改的版本来处理 multiline-record-writer 问题

public class MultiOutputItemWriter implements ItemWriter<Object> 

private JdbcBatchItemWriter<ClassFoo> delegateFoo;
private JdbcBatchItemWriter<ClassBar> delegateBar;

public void write(List<? extends Object> items) throws Exception 
       // if you have different types of items
       // check Object Class
       // add to new List<Classfoo>
       // call delegate e.g. delegateFoo.write(List with ClassFoo);
       //
       // or if you have complex objects
       // same procedure as above, but with
       // add to new List<Classfoo> with item.getClassFoo
 

如果你使用 FlatFileItemWriter,别忘了register the delegates as ItemStreams(这样 spring batch 会为你打开/关闭它们)

【讨论】:

谢谢迈克尔。我继续寻找答案,并或多或少地找到了相同的解决方案。我的项目处理器当前正在生成单个项目,但我可以修改它以返回项目列表。我计划使用单个编写器并将多个相同类型的项目写入表中。我会试一试,看看是否适合我。 这对我有用。我使用了一个处理器,该处理器返回项目列表和上面建议的作者。但是我使用带有批量更新的普通 jdbc 模板将项目插入数据库。关键部分是 'List项目'。我不熟悉这个符号,并试图从列表中读取项目。再次感谢您的帮助。

以上是关于使用弹簧批处理读取一个记录/项目并写入多个记录/项目的主要内容,如果未能解决你的问题,请参考以下文章

DynamoDB - 如何计算查询的读取吞吐量

运行弹簧批处理作业的多个实例时出现死锁

如何从 RODBC 读取 300 万条记录并写入文本文件

使用存储过程从 sql server 快速读取百万条记录,并使用 java 和 spring boot 将其写入 csv

来自管道的多个固定大小记录的读取器

服务器上有个2万条记录的MySQL数据表,读取并写入本地数据库,怎么这么慢啊?