2017-03-20 103 views
0

我为spring批处理使用java配置(spring-boot)。我有一个员工ID列表,对于每个ID,我需要运行一个查询(如下图),然后处理数据。使用JdbcCursorItemReader进行动态SQL查询

select * from history where employee_id = ? 

我知道我们可以使用reader.setPreparedStatementSetter来动态设置上述SQL中的参数。但是,我不确定如何重复列表中每个员工ID的批处理过程。即使我将reader()标记为@StepScope,读者也只会被调用一次。 (即),批次只运行一次。任何帮助表示赞赏。

List employeeIds = new ArrayList(); 
    employeeIds.add(1); 
    employeeIds.add(2); 

    @Bean 
    @StepScope 
    public ItemReader<History> reader() { 
     JdbcCursorItemReader<History> databaseReader = new JdbcCursorItemReader<>(); 
     databaseReader.setSql("select * from history where employee_id = ?"); 
     databaseReader.setPreparedStatementSetter(..); 
     .... 

     return databaseReader; 
    } 


    @Bean 
    public Step step(StepBuilder stepBuilder){ 
     return stepBuilderFactory.get("sample"). 
       .reader(reader()) 
       .processor(processor()) 
       .writer(writer()) 
       .build(); 
    } 
+0

这是一种常见模式(http://docs.spring.io/spring-batch/reference/html/patterns.html#drivingQueryBasedItemReaders)。您的阅读器从ID列表中返回ID,并且您当前的阅读器必须转换为处理器 –

+0

嗯,可以将一个ItemReader映射到多个ItemProcessor吗?因为我希望ItemProcessor为原始列表中的每个ID运行。 –

+0

是的,使用复合物品处理器(http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/item/support/CompositeItemProcessor.html) –

回答

2

所以首先,我不建议你这样做。从理论上讲,几乎总是在实践中,打开单个游标比每次单独查询都更有效率。

“更好”的方法是将ID列表插入登台表/驱动表(通常在先前的步骤中,每当您从原始源获取该ID列表时),然后将查询更改为类似:

select * from history where employee_id in (select id from driving_table) 

或者,你可以在最低限度,至少你的查询更改为:

select * from history where employee_id in (?) 

和ID到它的列表传递(注意这里一些数据库限制查询中的参数数量)。如果您的列表可能会超过此限制,则需要打开一个新的光标,并在列表中进行有效分页。

+0

谢谢。该列表包含大约200000条记录 - 因此“IN”不起作用。我可以使用JOIN来代替。 –

+0

绝对做加入。它将比将数据拉回仅仅是为了再次查询并且将减少不必要的I/O更好。 –