【问题标题】:Spring Batch job parameters limited to 250 chars?Spring Batch 作业参数限制为 250 个字符?
【发布时间】:2013-04-09 14:59:35
【问题描述】:

我正在使用 ItemReader/ItemWriter 设置 Spring Batch Job,以将数据集从 Oracle DB 导出到 CSV/Excel/PDF。对于读者部分,我使用的是JdbcCursorItemReader

默认情况下,需要将 SQL 语句传递给阅读器以提取数据集 - 这是我的阅读器配置:

<bean id="readErgebnis" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step">
    <property name="dataSource" ref="dataSource" />
    <property name="sql" value="#{jobParameters['stmt']}" />
    <property name="rowMapper">
        <bean class="myFancyRowMapper" />
    </property>
</bean>

所以我在 JobParametersBuilder 中添加了 SQL 语句...

JobParametersBuilder builder = new JobParametersBuilder(); 
builder.addString("stmt", sql);

应该没问题。但是,执行作业失败并显示SQLException

现在我知道 Spring Batch 正在将所有内容记录到它的记录表中​​,但存在问题 - 参数字符串(包含 SQL)限制为 250 个字符。查看 BATCH_JOB_PARAMS 表的定义:

CREATE TABLE BATCH_JOB_PARAMS  (
    JOB_INSTANCE_ID NUMBER(19,0) NOT NULL ,
    TYPE_CD VARCHAR2(6) NOT NULL ,
    KEY_NAME VARCHAR2(100) NOT NULL , 
    STRING_VAL VARCHAR2(250), 
    DATE_VAL TIMESTAMP DEFAULT NULL ,
    LONG_VAL NUMBER(19,0) ,
    DOUBLE_VAL NUMBER ,
    constraint JOB_INST_PARAMS_FK foreign key (JOB_INSTANCE_ID)
    references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
);

Spring Batch 将每个作业参数存储在一个新行中,因此 SQL 语句进入限制为 250 个字符的 STRING_VAL 列。我检查了其他数据库系统(MySQL 和 DB2)的 DDL,似乎到处都限制为 250 个字符。我现在将该列更改为CLOB,工作正常并且我的工作运行。

我的问题:我简直不敢相信它打算通过批处理作业存储限制为 250 个字符的作业参数。那么对于我的场景是否有更好的实现,或者它是否旨在更改 BATCH_JOB_PARAMS 表中参数列的默认值?

【问题讨论】:

  • 不,您不应该修改元数据架构。查看我的回复。

标签: java oracle spring spring-batch


【解决方案1】:

不要将 SQL 作为作业的参数传递。而是创建一个扩展实现 InitializingBean 的 JdbcCursorItemReader 的类。

package xxx.readers;

public class MyReader  extends  JdbcCursorItemReader<AnObjet> implements InitializingBean{


@Override
public void afterPropertiesSet() throws Exception {
        // set the SQL

    String SELECT_PAYMENT = "SELECT * from table"
    super.setSql(SELECT_PAYMENT);

    }
}

这样,当你的 bean 在启动时由 spring 上下文初始化时,你的 sql 将被设置。

如果您需要添加 where 子句,请使用 PreparedStatementSetter 并将其添加到配置中。

    <bean id="myReader" class="xxx.readers.MyReader">
    <property name="dataSource" ref="aDataSource" />
    <property name="rowMapper" ref="aMapper" />     
    <property name="preparedStatementSetter" ref="yourPreparedStatementSetter" />
</bean>

preparedStatementSetter 示例:

package fcdq.iemt.batch.concilliation.utils;

import java.sql.PreparedStatement;
 import java.sql.SQLException;

 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.PreparedStatementSetter;
 import org.springframework.stereotype.Component;



 @Component("aPrStatSetter")
 public class RunNoSetter implements PreparedStatementSetter {


public void setValues(PreparedStatement ps) throws SQLException {
    ps.setString(1, "hello");
    ps.setString(2, "Hola");
    ps.setTimestamp(3, aTimestamp);
}
 }

preparedStatementSetter 将在运行时被调用以替换 ?在你的 where 子句中。

希望有帮助。

【讨论】:

  • 谢谢,这行得通。然而,它更像是一种解决方法,因为我想记录已执行的 SQL 语句——而该信息现在丢失了。当然,可以将语句记录在不同的(自定义)日志表中。你会推荐这个还是有其他方法?除了日志记录问题之外,还有什么理由不将 SQL 作为参数传递?
  • 我会使用 log4j 在文件或其他数据库中记录 SQL。 srping 的元数据用于控制和了解作业的状态。例如,如果你只在job参数中传递SQL,你会发现你的job只能运行一次......因为spring batch不允许你运行2个具有相同参数值的job。这就是他如何知道工作是否运行的方式。您的 SQL 更像是一个步骤参数,而不是一项工作。最后,我会说,按照设计,将 SQL 作为作业参数传递是错误的。想象一下,如果你的工作有 10 个步骤……你必须通过 10 个 SQL!
  • 好点。我的工作是一步到位的,但当然可以随时改变。
猜你喜欢
  • 2017-06-15
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 2014-02-09
  • 2018-08-31
  • 2014-12-10
相关资源
最近更新 更多