从xml文件读取Spring批处理并写入Database . 需要step1自动为step2生成密钥

如下面的步骤1中的代码所示,我正在读取users.xml并在步骤2中写入数据库我正在读取userdetails.xml并写入数据库,但我需要step1自动生成tbl_user的键作为step2 . 我怎样才能做到这一点?

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:batch="http://www.springframework.org/schema/batch"        
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/batch 
        http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

<import resource="../config/context.xml" />
<import resource="../config/database.xml" />               


<bean id="xmlItemReader1" class="org.springframework.batch.item.xml.StaxEventItemReader">
    <property name="resource" value="file:xml/outputs/users.xml" />
    <property name="fragmentRootElementName" value="user" />
    <property name="unmarshaller" ref="userUnmarshaller"/>                    
</bean>

<bean id="xmlItemReader2" class="org.springframework.batch.item.xml.StaxEventItemReader">
    <property name="resource" value="file:xml/outputs/userdetails.xml" />
    <property name="fragmentRootElementName" value="userdetail" />
    <property name="unmarshaller" ref="userUnmarshaller"/>                    
</bean>

<bean id="itemProcessor1" class="com.qmetry.recovery.mapper.UserItemProcessor" />

<bean id="itemProcessor2" class="com.qmetry.recovery.mapper.UserDetailItemProcessor" />

<job id="testJob2" xmlns="http://www.springframework.org/schema/batch">
        <step id="step2_1">
            <tasklet transaction-manager="transactionManager">
                <chunk reader="xmlItemReader1" writer="databaseItemWriter1" processor="itemProcessor1"
                       commit-interval="100" />
            </tasklet>                
        <listeners>                
            <listener ref="testListener" />
        </listeners>            
        </step>
        <step id="step2_2">
            <tasklet transaction-manager="transactionManager">
                <chunk reader="xmlItemReader2" writer="databaseItemWriter2" processor="itemProcessor1"
                       commit-interval="100" />
            </tasklet>                
        </step>            
</job>
<bean id="testListener" class="com.qmetry.recovery.mapper.TestListener" scope="step" />

<bean id="databaseItemWriter1" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
    <property name="dataSource" ref="dataSource" />
    <property name="sql">
        <value>
            <![CDATA[        
                insert into TBL_USER(USERNAME,EMAILID) 
                values (?, ?)                        
            ]]>
        </value>
    </property>

     <!--We need a custom setter to handle the conversion between Jodatime LocalDate and MySQL DATE BeanPropertyItemSqlParameterSourceProvider--> 
    <property name="itemPreparedStatementSetter">
        <bean class="com.qmetry.recovery.mapper.UserItemPreparedStatementSetter"/>
    </property>
</bean> 
<bean id="databaseItemWriter2" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
    <property name="dataSource" ref="dataSource" />
    <property name="sql">
        <value>
            <![CDATA[        
                insert into TBL_USERDETAIL(USERID,CONTACT) 
                values (?, ?)
            ]]>
        </value>
    </property>

     <!--We need a custom setter to handle the conversion between Jodatime LocalDate and MySQL DATE BeanPropertyItemSqlParameterSourceProvider--> 
    <property name="itemPreparedStatementSetter">
        <bean class="com.qmetry.recovery.mapper.UserDetailItemPreparedStatementSetter"/>
    </property>
</bean>

users.xml中

<?xml version="1.0" encoding="UTF-8"?><users>
    <user>
        <userId>1</userId>
        <userName>Taher</userName>
        <emailId>taher.tinwala@hotmail.com</emailId>
    </user>
</users>

userdetails.xml

<?xml version="1.0" encoding="UTF-8"?><userdetails>
    <userdetail>
        <userDetailId>1</userDetailId>
        <userId__TblUser>1</userId__TblUser>
        <contact>1111111111</contact>
    </userdetail>
    <userdetail>
        <userDetailId>2</userDetailId>
        <userId__TblUser>1</userId__TblUser>
        <contact>2222222222</contact>
    </userdetail>
    <userdetail>
        <userDetailId>4</userDetailId>
        <userId__TblUser>1</userId__TblUser>
        <contact>4444444444</contact>
    </userdetail>
</userdetails>

回答(1)

2 years ago

您需要将数据传递到将来的步骤 . 有关解释性文档,请参阅http://docs.spring.io/spring-batch/trunk/reference/html/patterns.html#passingDataToFutureSteps

我已经从文档中实现了示例,并将其调整为您的配置,并在此处进行了一些假设 .

在读取(或写入,取决于您获取要传递的数据时)的步骤1中,您需要将数据存储在StepExecution中 . 将以下内容添加到xmlItemReader:

public class YourItemReader implements ItemReader<Object>
    private StepExecution stepExecution;

    public void read(Object item) throws Exception {
        // ...

        ExecutionContext stepContext = this.stepExecution.getExecutionContext();
        stepContext.put("tbl_user", someObject);
    }

    @BeforeStep
    public void saveStepExecution(StepExecution stepExecution) {
        this.stepExecution = stepExecution;
    }

你的xml看起来像这样:

<step id="step2_1">
    <tasklet transaction-manager="transactionManager">
        <chunk reader="xmlItemReader1" writer="databaseItemWriter1" processor="itemProcessor1" commit-interval="100" />
    </tasklet>                
    <listeners>                
        <listener ref="testListener" />
        <listener ref="promotionListener"/>
    </listeners>
</step>

添加promotionListener bean:

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

最后,您需要在步骤2中检索该值 . 再次假设您在步骤2的阅读器中需要它,您在步骤2中的阅读器需要添加以下代码:

public class YourItemReader2 implements ItemReader<Object>
    private Object someObject;

    @BeforeStep
    public void retrieveInterstepData(StepExecution stepExecution) {
        JobExecution jobExecution = stepExecution.getJobExecution();
        ExecutionContext jobContext = jobExecution.getExecutionContext();
        this.someObject = jobContext.get("tbl_key");
    }

现在您可以访问步骤1中读取的值 .

EDIT - adding some example configuration for an extra read step:

在步骤1之后,使用以下阅读器添加一个简单的步骤2,以从数据库中获取新值

<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader"
    scope="step">
    <property name="dataSource" ref="dataSource" />            
    <property name="sql">
        <value>
            <![CDATA[
                YOUR SELECT STATEMENT
            ]]>
        </value>
    </property>
    <property name="rowMapper" ref="rowMapper" />     
</bean>

还有一个简单的rowMapper bean

<bean id="rowMapper" class="exampleRowMapper" />

您必须明确编写exampleRowMapper以反映您获取的数据 . 例如:

public class ExampleRowMapper implements ParameterizedRowMapper<String> {

    @Override
    public String mapRow(ResultSet rs, int rowNum) throws SQLException {
        return String.valueOf(rs.getString(1));
    }

}

在你的编写器中,你添加了stepexecution,你将把你的值存储在步骤执行上下文中:

public class DummyItemWriter implements ItemWriter<Object> {
    private StepExecution stepExecution;

    @Override
    public void write(List<? extends Object> item) throws Exception {
        ExecutionContext stepContext = this.stepExecution.getExecutionContext();
        stepContext.put("someKey", someObject);
    }    
}

而作者的 beans 子:

<bean id="savingDummyWriter" class="your.package.DummyItemWriter" />

并将读者和作者包装在一个步骤中 .

<step id="step2">
    <tasklet>    
        <chunk reader="itemReader" writer="dummyItemWriter" commit-interval="1" />    
    </tasklet>        
    <listeners>
        <listener ref="promotionListener"/>
    </listeners>
</step>