More on Spring Batch Reader

Spring Batch Job is composed of Reader, Processor and Writer. This post shows some more details on Reader.

Reader is the implementation of org.springframework.batch.item.Reader. I recommend to use the following implementations.

  • AmqpItemReader (org.springframework.batch.item.amqp.AmqpItemReader) : to interact with queue such as RabbitMQ
  • FlatFileItemReader (org.springframework.batch.item.file.FlatFileItemReader) : to interact with a file
  • JdbcCursorItemReader (org.springframework.batch.item.database.JdbcCursorItemReader) : to interact with a database

Or you can make a custom Reader.

I’ll show you some examples with JdbcCursorItemReader. But the tips can be applied to the other implementations.

Passing parameters

When reading a table, we need to pass parameters to the sql. JdbcCursorItemReader use JDBC sql format. Therefore, parameters are defined as “?” marker. (For example, SELECT COL1, COL2, COL3 FROM TB_SOURCE WHERE COL1 = ?)

JdbcCursorItemReader use a PreparedStatementSetter bean to set parameter. The following is a sample Reader definition.

<bean id="SourceMapper"
class="test.rowmapper.TbSourceMapper"/>
<bean id="ParameterSetter" class="test.reader.TestParameterSetter">
<property name="param" value="col1-1"/>
</bean>
<bean id="TestReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="testDataSource"/>
<property name="sql"
value="SELECT COL1, COL2, COL3
FROM TB_SOURCE
WHERE COL1 = ?"/>
<property name="rowMapper"
ref="SourceMapper"/>
<property name="preparedStatementSetter" ref="ParameterSetter"/>
<property name="fetchSize" value="100" />
<property name="maxRows" value="0" />
</bean>

Notice that TestReader has preparedStatementSetter  property.

The following is the sample parameter setter bean.

import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.springframework.jdbc.core.PreparedStatementSetter;
public class TestParameterSetter implements PreparedStatementSetter {
private String param;
public void setParam(String param) {
this.param = param;
}
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(1, this.param);
}
}

Parameter setter must implement org.springframework.jdbc.core.PreparedStatementSetter.

Passing parameter from outer environment

Above sample is setting parameter value at Spring context.xml. But sometimes, we need to get the value from outer environment. Spring Batch supports it with JobParameter. It can be set when we invoke Spring Batch job.

The following is modified Reader definition.

<bean id="SourceMapper"
class="test.rowmapper.TbSourceMapper"/>
<bean id="ParameterSetter" class="test.reader.TestParameterSetter" scope="step">
<property name="param" value="#{jobParameters['param1']}"/>
</bean>
<bean id="TestReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="testDataSource"/>
<property name="sql"
value="SELECT COL1, COL2, COL3
FROM TB_SOURCE
WHERE COL1 = ?"/>
<property name="rowMapper"
ref="SourceMapper"/>
<property name="preparedStatementSetter" ref="ParameterSetter"/>
<property name="fetchSize" value="100" />
<property name="maxRows" value="0" />
</bean>

Now, intead of static value, the parameter setter is using “#{jobParameters[‘param_name‘]}” syntax.

JobParameter values are set at job invocation time. The following is a sample invocation program.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
public class TestRun2_2 {
public static void main(String[] args) throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring/job-test02-02-context.xml"});
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job testJob = context.getBean("TestJob02", Job.class);
JobParameters jobParameters = new JobParametersBuilder()
.addString("start_time", Long.toString(System.currentTimeMillis()))
.addString("param1", "col1-1")
.toJobParameters();
jobLauncher.run(testJob, jobParameters);
//
((ClassPathXmlApplicationContext)context).close();
}
}

Above sample shows that JobParameters.addString(“param_name”, “param_value”) is setting the job parameter.
And also notice that ParameterSetter’s bean scope is “step”. Spring Batch is extending bean scope with “step” and “job”. (More on Spring Batch Scope) To access to JobParameter, bean’s scope must be “step” or “job”.

You can download the full sources from github.

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.