1

我正在使用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>

所以我将 SQL 语句添加到 JobParametersBuilder...

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 表中参数列的默认值?

4

1 回答 1

3

不要将 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 子句中。

希望它有所帮助。

于 2013-04-09T15:11:29.427 回答