【问题标题】:Spring Batch read from database once, write to another database and write to CSVSpring Batch 从数据库读取一次,写入另一个数据库并写入 CSV
【发布时间】:2017-05-16 16:26:19
【问题描述】:

我是 Spring Batch 的新手,并尝试在我的位置实现批处理作业

  1. 从 MySQL 数据库中读取
  2. 将结果写入 CSV 文件
  3. 对 MySQL 结果集进行一些处理并写入另一个数据库。

我查看了this question on StackOverflow,但主要接受的答案基本上是实现从数据库读取两次的两个步骤:

<job id="myJob">
    <step id="step1" next="step2">
        <tasklet>
            <chunk reader="reader" writer="typeAwriter"/>
        </tasklet>
    </step>
    <step id="step2">
        <tasklet>
            <chunk reader="reader" processor="processor" writer="typeBwriter"/>
        </tasklet>
    </step>
</job>

难道没有比从 MySQL 数据库读取两次更有效的方法吗?例如,如果您的查询很大并且拖累系统性能怎么办?

【问题讨论】:

    标签: spring spring-batch


    【解决方案1】:

    你需要的是块策略而不是 tasklet。 ItemReader 将从您的数据库中读取块,处理器将处理您的数据,然后您可以为每个项目将它们发送到可以写入数据库和文件的 ItemWriter。这是许多可能的策略之一,我不知道您的业务逻辑的详细信息,但我认为这些信息足以让您继续自己的想法。

    <?xml version="1.0" encoding="UTF-8"?>
    <job id="customerJob" xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd"
    version="1.0">
    
        <step id="step1">
            <chunk item-count="5">
                <reader ref="itemReader"/>
                <processor ref="itemProcessor"/>
                <writer ref="itemWriter"/>
            </chunk>
        </step>
    </job>
    

    这是 JSR-352 XML 类型,对于 Spring 你有相应的方法。

    【讨论】:

    • 谢谢蒂姆。但我不确定这是否完全回答了我的问题。您是否建议 itemWriter 包含同时写入 CSV 和数据库的逻辑?如果是这样,它是如何实施的?我找到了一个不错的解决方案,做更多的挖掘——检查我自己的答案,让我知道你的想法!
    • ItemWriter的实现取决于业务逻辑的细节,当然你可以在一行中处理一些实体,下一行传递实体进行处理写入文件(反之亦然) .
    【解决方案2】:

    我会继续回答我自己的问题。有多种方法可以做到这一点,但我发现先将属性和对象保存到StepExecutionContext,然后在步骤完成后将它们提升到JobExecutionContext 效果很好。它也被记录得很彻底here.

    第 1 步:

    在您的 Writer / Reader 中声明一个私有 StepExecution。然后,在您的读/写方法中创建步骤上下文,并将您的数据作为键/值对放入:

    ExecutionContext stepContext = this.stepExecution.getExecutionContext();
    stepContext.put("someKey", someObject);
    

    第 2 步:ExecutionContextPromotionListener 添加到步骤的 bean 配置中。 ExecutionContextPromotionListener 必须包含一个名为 Keys 的 String[] 属性,其中包含您希望提升到超出您的步骤的 Job 范围的键,类似于 LinkedIn article 中的此实现:

    @Bean
    public ExecutionContextPromotionListener promotionListener() {
        ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
        listener.setKeys( new String[] { "entityRef" } );
        return listener;
    }
    

    第 3 步: 您还需要在步骤执行之前将 StepExecution 添加到您的 Writer 中:

    @BeforeStep
    public void saveStepExecution( StepExecution stepExecution ) {
        this.stepExecution = stepExecution;
    } 
    

    第 4 步: 这将使您的write() 方法可以访问stepExecution 实例,它可以在其中访问stepContext 以便您保存数据。例如,你可以写

    write() {
        ... // write logic
    
        ExecutionContext stepContext = this.stepExecution.getExecutionContext();
        stepContext.put("keyYouWantToPutIn", theCorrespondingDataObject);
    }
    

    最后,在下一步中,您可以检索此数据(示例直接来自Spring Batch documentation

    @BeforeStep
    public void retrieveInterstepData(StepExecution stepExecution) {
        JobExecution jobExecution = stepExecution.getJobExecution();
        ExecutionContext jobContext = jobExecution.getExecutionContext();
        this.someObject = jobContext.get("someKey");
    }
    

    不过,这一次请注意,它是从 jobContext 而非 stepContext 访问的——它已被提升!

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 2012-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      相关资源
      最近更新 更多