2013-04-09 60 views
1

我使用ItemReader/ItemWriter设置了一个Spring批处理作业,可将数据集从Oracle DB导出到CSV/Excel/PDF。对于阅读器部分,我使用的是JdbcCursorItemReaderSpring批处理作业参数限制为250个字符?

默认情况下它是必要的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

现在我知道,春天批次记录一切,它的日志表,有问题 - 参数字符串(含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语句进入STRING_VAL列被限制为250个字符。我检查了其他数据库系统(MySQL和DB2)的DDL,它似乎只限于250个字符。我现在将该栏目更改为CLOB,工作正常,工作正常。

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

+0

不,你不应该修改元数据模式。看到我的回应。 – Cygnusx1 2013-04-09 15:15:22

回答

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); 

    } 
} 

这样,当Spring在启动时由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子句中。

希望它有帮助。

+0

谢谢,这是有效的。然而,它更像是一种解决方法,因为我想记录已执行的SQL语句 - 而且现在信息丢失了。当然,可以在不同的(自定义)日志表中记录该语句。你会推荐还是以另一种方式?除了日志记录问题之外,是否还有更多理由不通过SQL作为参数? – 2013-04-09 16:02:34

+1

我会在文件或其他数据库中记录log4j的SQL。 srping的元数据用于控制和了解作业的状态。例如,如果只传递job参数中的SQL,则会发现只能运行一次作业...因为spring批处理不允许使用相同的参数值运行2作业。多数民众赞成他如何知道工作是否运行。你的SQL更像是一个步骤参数,然后是一份工作。最后,我想说,通过设计将SQL作为工作参数传递是错误的。想象一下,如果你的工作会有10个步骤......你将不得不通过10个SQL! – Cygnusx1 2013-04-09 17:21:18

+0

好点。我的工作是一步一步的,但当然可以随时改变。 – 2013-04-09 17:41:27

相关问题