运行数据库项阅读器以获取参数列表

时间:2014-07-21 21:34:43

标签: spring-batch

我有一个弹簧批量数据库项目阅读器,如下所示:

<beans:bean id="MyItemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step">
         <beans:property name="dataSource" ref="MyDataSource" />
         <beans:property name="sql" value="SELECT MY_DATE, COL1, COL2 FROM MYSCHEMA.MYTABLE WHERE MY_DATE = ?" />
         <beans:property name="rowMapper">
             <beans:bean name="mapper" class="com.mypackage.MyRowMapper" />
         </beans:property>
</beans:bean>

很明显,读者需要一个参数,我可以使用preparedStatementSetter提供该参数。

然而,问题是,我有一个参数列表,即十个日期。

我希望将所有十个日期的读者一个接一个地运行10次,然后只运行一次编写器以写入所有日期的所有读取数据。

我不能在QUERY的条件下改变,包括&#34; IN&#34;条款。我的要求是一个接一个地传递日期。

我可以使用促销听众以任何形式向读者提供10个日期。对于例如包含键值对的10个日期的地图或10个日期的列表等。

我怎样才能做到这一点?

如果有人可以指出我的自定义数据库项目阅读器示例,那就太棒了。

感谢阅读!

2 个答案:

答案 0 :(得分:2)

您不能将MultiResourceItemReader与自定义PreparedStatementSetter配对的策略与您的参数进行后期绑定,因为“MyItemReader”会针对步骤进行一次评估。
我的建议是创建一个自定义ItemReader保留List<Date>并循环浏览此列表,直到它用完为止;阅读是使用委托和?替换是手动完成的。

public class DateListPreparedStatementSetter implements PreparedStatementSetter {
    private Date date;
    public void setDate(Date date) {
        this.date = date;
    }
    public void setValues(PreparedStatement ps) throws SQLException {
        ps.setDate(0,  date);
    }
}

public class DateListItemReader<T> extends AbstractItemStreamItemReader<T>
{
    List<Date> dateList;
    int listIndex = -1;
    DateListPreparedStatementSetter pss;
    ItemReader<T> delegate;

    public void setDateList(List<Date> dateList) {
        this.dateList = dateList;
    }

    public void setDelegate(ItemReader<T> delegate) {
        this.delegate = delegate;
    }

    public void setPss(DateListPreparedStatementSetter pss) {
        this.pss = pss;
    }

    public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        T next = delegate.read();
        //  No more elements...
        if(null == next)
        {
            //  Close delegate
            ++listIndex;
            //  ...but more dates!
            if(listIndex < dateList.size())
            {
                pss.setDate(dateList.get(listIndex));
                //  Open delegate
                //  Recursive read
                next = read();
            }
        }
        return next;
    }

    @Override
    public void open(ExecutionContext executionContext) {
        //  Restore last index
        listIndex = executionContext.getInt("dateListIndex",-1);
        ((ItemStream)delegate).open(executionContext);
        super.open(executionContext);
    }

    @Override
    public void update(ExecutionContext executionContext) {
        //  Save last index
        executionContext.putInt("dateListIndex", listIndex);
        ((ItemStream)delegate).update(executionContext);
        super.update(executionContext);
    }

    @Override
    public void close() {
        ((ItemStream)delegate).close();
        super.close();
    }
}

<bean name="myPSS" class="DateListPreparedStatementSetter" />
<bean name="myReader" class="DateListItemReader">
  <property name="dateList">
    <list>
      <value>01/01/2010</value>
      <value>01/01/2011</value>
    </list>
  </property>
</bean>
<bean name="MyItemReader">
  <!-- Other props...  ->
  <property name="preparedStatementSetter" ref="myPSS" />
</bean>

我没有测试过代码,但这个想法应该很明确。

答案 1 :(得分:1)

一种方法是开发复合项目阅读器。请查看these posts。复合方法的缺点是您需要定义(基于您的示例)10个项目读取器(每个日期一个)。你拥有的日期越多,就越糟糕。

我不知道它是否可以接受,但另一种方法是在存储过程中封装不可更改的查询。在存储过程中,您可以执行循环,调用不可更改的查询,将单个日期传递给它。在春季批次中,您可以使用StoredProcedureItemReader

您还可以尝试扩展JdbcCursorItemReader,迭代doRead方法中的日期,但我查看了源代码,但我不明白spring如何处理游标的打开和关闭。 ..所以我担心它不像听起来那么简单......