【问题标题】:Spring Batch, Update statement in a writer? Throwing IllegalArgumentExceptionSpring Batch,编写器中的更新语句?抛出 IllegalArgumentException
【发布时间】:2018-11-13 22:29:37
【问题描述】:

尽量简洁,

我有一个主步骤,将执行拆分为并行从属。

这些从站每个都有自己的上下文,其中存储了它们执行的线程的 ID,runNumber。它们是读取器、处理器、写入器步骤。这个奴隶的写是我关心的。我有一个CompositeItemWriter,它有一个编写器,我想做一个 SQL 更新语句来更新线程在数据库中的成功。作者如下:

@Bean
@StepScope
public JdbcBatchItemWriter<TraceDataDto> controlSuccessWriter(
        @Value("#{jobExecutionContext['runNumber']}") int runNumber,
        @Qualifier("veDataSource") DataSource veDataSource) {
    JdbcBatchItemWriter<TraceDataDto> mysqlWriter = new JdbcBatchItemWriter<>();

    mysqlWriter.setDataSource(veDataSource);

    String sql = "UPDATE control SET status=1 WHERE run_number=" + runNumber;

    mysqlWriter.setSql(sql);

    return mysqlWriter;
}

现在,我遇到了这个问题,因为它会吐出一个错误:

java.lang.IllegalArgumentException:使用带有“?”的 SQL 语句 占位符需要一个 ItemPreparedStatementSetter

现在我知道有一条路径可以创建一个实现 ItemPreparedStatementSetter 的自定义类,但我担心通过将单个值映射到对象会产生不必要的开销。

有没有一种简单的方法可以让我在从属步骤中执行这个更新语句?

【问题讨论】:

    标签: java spring spring-boot spring-batch


    【解决方案1】:

    Spring Batch 提供的 ItemWriter 实现预计将持久化项目。这不是你想要做的,所以我建议创建一个 ItemWriter(或者更好的监听器),它只使用 JdbcTemplate 来执行你需要的查询。

    【讨论】:

      【解决方案2】:

      这对我有用:

      import java.util.ArrayList;
      import java.util.List;
      import javax.sql.DataSource;
      
      import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
      import org.springframework.batch.item.database.JdbcBatchItemWriter;
      import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
      import org.springframework.beans.factory.annotation.Autowired;
      
      ...
      
      @Autowired
      public DataSource dataSource;
      
      ...
      
      JdbcBatchItemWriter<TraceDataDto> updateItemWriter = new JdbcBatchItemWriterBuilder<TraceDataDto>()
              .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
              .sql("UPDATE control SET status=1 WHERE run_number=" + runNumber + 
                  " AND LENGTH(control.<someNonNullCharColumn>) >= LENGTH(:<TraceDataDto::someStringField>")
              .dataSource(dataSource).build();
      // dummy list to trigger at least one statement
      List<TraceDataDto> dummyList = new ArrayList<>();
      // here at least TraceDataDto::someStringField should be set to ""
      TraceDataDto dummyTdd = new TraceDataDto("a", "b", 2, 3.14, ...);
      dummyList.add(dummyTdd);
      // to avoid exception: 
      // java.lang.NullPointerException: null
      // at org.springframework.batch.item.database.JdbcBatchItemWriter$1.doInPreparedStatement(JdbcBatchItemWriter.java:190)
      deleteItemWriter.afterPropertiesSet();
      try {
          updateItemWriter.write(dummyList);
      } catch (Exception e) {
          // no action
      }
      

      这里的技巧是使用包含:fieldName 占位符的SQL 语句,这样您就可以使用BeanPropertyItemSqlParameterSourceProvider 而不是ItemPreparedStatementSetter
      这只是一个示例,您想在 WHERE 子句中使用 :fieldName 选择所有行,这与您的实际子句进行 AND 运算。

      【讨论】:

        猜你喜欢
        • 2019-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-04
        • 1970-01-01
        • 2017-10-14
        相关资源
        最近更新 更多