2016-12-05 53 views
0

下面我有春天批處理作業:如何運行在一個循環中Spring Batch的一個步:更新

<job id="MyBatchJob" job-repository="jobRepository"> 

    <step id="ConfigurationReadStep"> 
     <tasklet ref="ConfigurationReadTasklet" transaction-manager="jobRepository-transactionManager"/> 
     <next on="COMPLETED" to="NextStep" /> 
    </step>   

    <step id="NextStep"> 
    <tasklet transaction-manager="jobRepository-transactionManager"> 
     <chunk reader="myItemReader" writer="myItemWriter" commit-interval="1000"/> 
    </tasklet> 
    </step> 

    <listeners> 
     <listener ref="jobListener" /> 
    </listeners>  

</job> 

它的第一步爲配置讀取步驟,其中,後一些業務邏輯,我有遇到查詢列表。對於例如說10個查詢。我知道我可以使用JobExecutionContextPromotionListener來宣傳此列表。

但是,我想將這個查詢一個一個地加入到我的下一步的閱讀器中,作爲閱讀器查詢並在循環中運行該步驟,直到所有閱讀器查詢被消耗完。我想將每個查詢都作爲Spring批處理場景運行,因爲它們可能會返回大量項目。

我該怎麼做?

*********************************** ***********************************更新********** ************************

這就是我要做的:

<job id="MyJob" job-repository="jobRepository"> 

     <step id="ConfigurationReadStep"> 
      <tasklet ref="ConfigurationReadTasklet" transaction-manager="jobRepository-transactionManager"/> 
      <next on="COMPLETED" to="MyNextStep" />  
      <listeners> 
       <listener ref="promotionListener"/> 
      </listeners> 
     </step>   

    <step id="MyNextStep" next="limitDecision"> 
     <tasklet transaction-manager="jobRepository-transactionManager"> 
      <chunk reader="MyItemReader" writer="MyItemWriter" commit-interval="1000"/> 
     </tasklet> 
    </step> 

    <decision id="limitDecision" decider="limitDecider"> 
     <next on="CONTINUE" to="MyNextStep" /> 
     <end on="COMPLETED" /> 
    </decision> 

    <listeners> 
     <listener ref="jobListener" /> 
    </listeners> 

    </job> 

<beans:bean id="jobListener" class="com.hsbc.gbm.dml.integration.batch.listener.SimpleJobListener" /> 

<beans:bean id="promotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener"> 
    <beans:property name="keys" value="readerLimit,readerQueries,readerSQL" /> 
</beans:bean> 

    <beans:bean id="ConfigurationReadTasklet" class="com.mypackage.ConfigurationReadTasklet" scope="step"> 
    </beans:bean> 

<beans:bean id="MyItemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step"> 
    <beans:property name="dataSource" ref="myDataSource" /> 
    <beans:property name="sql" value="#{jobExecutionContext['readerSQL']}" /> 
    <beans:property name="rowMapper"> 
     <beans:bean name="mapper" class="com.mypackage.MyRowMapper" /> 
    </beans:property> 
</beans:bean> 

<beans:bean id="MyItemWriter" class="com.mypackage.MyItemWriter" scope="step"> 
    <beans:constructor-arg ref="myDataSource" /> 
</beans:bean> 

<beans:bean id="limitDecider" class="com.mypackage.StepLoopLimitDecider" scope="step"> 
    <beans:property name="readerQueries" value="#{jobExecutionContext['readerQueries']}" /> 
</beans:bean>  

在微進程,我會獲取閱讀器查詢列表。我將設置readerQuery作爲其中的第一步,然後轉到下一步,這將作爲彈簧批處理步驟正常運行。

一旦完成,我希望我的Decider檢查,如果有更多的讀者查詢,如果是,它將改變readerQuery下一個查詢並重新運行NextStep,否則工作將完成。以下是我的決策者:

public class StepLoopLimitDecider implements JobExecutionDecider { 

private List<String> readerQueries; 

private int count = 1; 

public FlowExecutionStatus decide(JobExecution jobExecution,StepExecution stepExecution) { 
    if (count >= this.readerQueries.size()) { 
     return new FlowExecutionStatus("COMPLETED"); 
    } 
    else { 
     System.out.println(count + ": "+readerQueries.get(count)); 
     jobExecution.getExecutionContext().put("readerSQL", readerQueries.get(count)); 
     count = count + 1; 
     return new FlowExecutionStatus("CONTINUE"); 
    } 
} 

public void setReaderQueries(List<String> readerQueries) { 
    this.readerQueries = readerQueries; 
} 
} 

但是,這是行不通的。第一次正確運行。但決策失敗,出現以下錯誤:

2016-12-06 14:46:24 ERROR AbstractJob:306 - Encountered fatal error executing job 
org.springframework.batch.core.JobExecutionException: Flow execution ended unexpectedly 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:141) 
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120) 
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114) 
    at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:348) 
    at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:565) 
Caused by: 
org.springframework.batch.core.job.flow.FlowExecutionException: Ended flow=MyBatchJob at state=MyBatchJob.limitDecision with exception 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:152) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124) 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135) 
    ... 6 more 
Caused by: 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.limitDecider': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:339) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190) 
    at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:182) 
    at $Proxy4.decide(Unknown Source) 
    at org.springframework.batch.core.job.flow.support.state.DecisionState.handle(DecisionState.java:43) 
    at org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean$DelegateState.handle(SimpleFlowFactoryBean.java:141) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144) 
    ... 8 more 
Caused by: 
java.lang.IllegalStateException: No context holder available for step scope 
    at org.springframework.batch.core.scope.StepScope.getContext(StepScope.java:197) 
    at org.springframework.batch.core.scope.StepScope.get(StepScope.java:139) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325) 
    ... 15 more 

有人可以幫助我做這項工作。

+0

的決定是不是Spring Batch的中的一個步驟,因此不能一步作用域。使這項工作的範圍和事情應該從我能看到的... –

回答

1

我建議您根據您的業務邏輯的結果動態地構建您的工作計算查詢。

但是,你不能用xml-configuration來做到這一點,所以我建議你使用java-config api。

我已經寫了幾個關於「如何動態創建工作」的類似問題的答案。看看他們,讓我知道,如果你需要furhter建議。

SpringBatch - javaconfig vs xml

Spring Batch Java Config: Skip step when exception and go to next steps

Spring batch repeat step ending up in never ending loop

Spring Batch - How to generate parallel steps based on params created in a previous step

Spring Batch - Looping a reader/processor/writer step

+0

謝謝。你可以請檢查我的問題的更新。我正在嘗試一種方法,但它不起作用。 – Nik

+0

這不起作用。 SpringBatch並不打算在單個作業啓動期間多次執行特定步驟。該框架保留了該步驟及其讀寫器的幾個內部狀態。您需要在運行時切入實例化的作業結構,並以某種方式重置該步驟以及讀者和作者的狀態。但是這很醜陋,而且很髒。絕對不是你想做的事情。 –

+0

正如我試圖解釋的,熟悉Java-API。然後用Java代碼而不是XML來創建你的Job。據我瞭解,在您啓動應用程序後,您可以確定必須創建的不同步驟。你可以用Java-Api來做到這一點。看看我的答案在這裏:http://stackoverflow.com/questions/37238813/spring-batch-looping-a-reader-processor-writer-step/37271735#37271735 –

相關問題