Skip to content

Commit 5f12a83

Browse files
committed
Add java configuration for the Jdbc cursor sample
Issue #3663
1 parent 1eab6f6 commit 5f12a83

File tree

8 files changed

+252
-71
lines changed

8 files changed

+252
-71
lines changed

spring-batch-samples/README.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,13 @@ remote client (such as JConsole from the JDK) which does not have
101101
Spring Batch on the classpath. See the Spring Core Reference Guide
102102
for more details on how to customise the JMX configuration.
103103

104-
### Jdbc Cursor and Batch Update
104+
### Jdbc Cursor and Batch Update sample
105105

106106
The purpose of this sample is to show to usage of the
107107
`JdbcCursorItemReader` and the `JdbcBatchItemWriter` to make
108108
efficient updates to a database table.
109109

110-
The `JdbcBatchItemWriter` accepts a special form of
111-
`PreparedStatementSetter` as a (mandatory) dependency. This is
112-
responsible for copying fields from the item to be written to a
113-
`PreparedStatement` matching the SQL query that has been
114-
injected. The implementation of the
115-
`CustomerCreditUpdatePreparedStatementSetter` shows best
116-
practice of keeping all the information needed for the execution in
117-
one place, since it contains a static constant value (`QUERY`)
118-
which is used to configure the query for the writer.
110+
[Jdbc Cursor and Batch Update sample](./src/main/java/org/springframework/batch/sample/jdbc/README.md)
119111

120112
### Amqp Job Sample
121113

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.batch.sample.jdbc;
17+
18+
import javax.sql.DataSource;
19+
20+
import org.springframework.batch.core.Job;
21+
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
22+
import org.springframework.batch.core.job.builder.JobBuilder;
23+
import org.springframework.batch.core.repository.JobRepository;
24+
import org.springframework.batch.core.step.builder.StepBuilder;
25+
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
26+
import org.springframework.batch.item.database.JdbcBatchItemWriter;
27+
import org.springframework.batch.item.database.JdbcCursorItemReader;
28+
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
29+
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
30+
import org.springframework.batch.sample.domain.trade.CustomerCredit;
31+
import org.springframework.batch.sample.domain.trade.internal.CustomerCreditIncreaseProcessor;
32+
import org.springframework.batch.sample.domain.trade.internal.CustomerCreditRowMapper;
33+
import org.springframework.context.annotation.Bean;
34+
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
36+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
37+
import org.springframework.jdbc.support.JdbcTransactionManager;
38+
39+
/**
40+
* @author Mahmoud Ben Hassine
41+
*/
42+
@Configuration
43+
@EnableBatchProcessing
44+
public class JdbcCursorReaderBatchWriterSampleJob {
45+
46+
@Bean
47+
public JdbcCursorItemReader<CustomerCredit> itemReader() {
48+
String sql = "select ID, NAME, CREDIT from CUSTOMER";
49+
return new JdbcCursorItemReaderBuilder<CustomerCredit>().name("customerReader")
50+
.dataSource(dataSource())
51+
.sql(sql)
52+
.rowMapper(new CustomerCreditRowMapper())
53+
.build();
54+
}
55+
56+
@Bean
57+
public JdbcBatchItemWriter<CustomerCredit> itemWriter() {
58+
String sql = "UPDATE CUSTOMER set credit = :credit where id = :id";
59+
return new JdbcBatchItemWriterBuilder<CustomerCredit>().dataSource(dataSource())
60+
.sql(sql)
61+
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
62+
.assertUpdates(true)
63+
.build();
64+
}
65+
66+
@Bean
67+
public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
68+
return new JobBuilder("ioSampleJob", jobRepository)
69+
.start(new StepBuilder("step1", jobRepository).<CustomerCredit, CustomerCredit>chunk(2, transactionManager)
70+
.reader(itemReader())
71+
.processor(new CustomerCreditIncreaseProcessor())
72+
.writer(itemWriter())
73+
.build())
74+
.build();
75+
}
76+
77+
// Infrastructure beans
78+
79+
@Bean
80+
public DataSource dataSource() {
81+
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
82+
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
83+
.addScript("/org/springframework/batch/core/schema-hsqldb.sql")
84+
.addScript("/org/springframework/batch/sample/jdbc/sql/schema.sql")
85+
.build();
86+
}
87+
88+
@Bean
89+
public JdbcTransactionManager transactionManager(DataSource dataSource) {
90+
return new JdbcTransactionManager(dataSource);
91+
}
92+
93+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
### Jdbc Cursor and Batch Update sample
2+
3+
## About
4+
5+
The purpose of this sample is to show to usage of the
6+
`JdbcCursorItemReader` and the `JdbcBatchItemWriter` to make
7+
efficient updates to a database table.
8+
9+
The `JdbcBatchItemWriter` accepts a special form of
10+
`PreparedStatementSetter` as a (mandatory) dependency. This is
11+
responsible for copying fields from the item to be written to a
12+
`PreparedStatement` matching the SQL query that has been
13+
injected. The implementation of the
14+
`CustomerCreditUpdatePreparedStatementSetter` shows best
15+
practice of keeping all the information needed for the execution in
16+
one place, since it contains a static constant value (`QUERY`)
17+
which is used to configure the query for the writer.
18+
19+
## Run the sample
20+
21+
You can run the sample from the command line as following:
22+
23+
```
24+
$>cd spring-batch-samples
25+
# Launch the sample using the XML configuration
26+
$>../mvnw -Dtest=JdbcCursorFunctionalTests#testLaunchJobWithXmlConfiguration test
27+
# Launch the sample using the Java configuration
28+
$>../mvnw -Dtest=JdbcCursorFunctionalTests#testLaunchJobWithJavaConfiguration test
29+
```
30+

spring-batch-samples/src/main/resources/jobs/iosample/jdbcCursor.xml

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:batch="http://www.springframework.org/schema/batch"
5+
xsi:schemaLocation="
6+
http://www.springframework.org/schema/batch https://www.springframework.org/schema/batch/spring-batch.xsd
7+
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
8+
9+
<batch:job id="ioSampleJob" xmlns="http://www.springframework.org/schema/batch">
10+
<batch:step id="step1">
11+
<batch:tasklet>
12+
<batch:chunk reader="itemReader" processor="itemProcessor" writer="itemWriter"
13+
commit-interval="2"/>
14+
</batch:tasklet>
15+
</batch:step>
16+
</batch:job>
17+
18+
<bean id="itemProcessor"
19+
class="org.springframework.batch.sample.domain.trade.internal.CustomerCreditIncreaseProcessor"/>
20+
21+
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
22+
<property name="dataSource" ref="dataSource"/>
23+
<property name="sql" value="select ID, NAME, CREDIT from CUSTOMER"/>
24+
<property name="verifyCursorPosition" value="true"/>
25+
<property name="rowMapper">
26+
<bean class="org.springframework.batch.sample.domain.trade.internal.CustomerCreditRowMapper"/>
27+
</property>
28+
</bean>
29+
30+
<bean id="itemWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
31+
<property name="assertUpdates" value="true"/>
32+
<property name="itemSqlParameterSourceProvider">
33+
<bean class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider"/>
34+
</property>
35+
<property name="sql" value="UPDATE CUSTOMER set credit = :credit where id = :id"/>
36+
<property name="dataSource" ref="dataSource"/>
37+
</bean>
38+
</beans>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
DROP TABLE CUSTOMER_SEQ IF EXISTS;
2+
DROP TABLE CUSTOMER IF EXISTS;
3+
4+
CREATE TABLE CUSTOMER_SEQ (
5+
ID BIGINT IDENTITY
6+
);
7+
INSERT INTO CUSTOMER_SEQ (ID) values (5);
8+
9+
CREATE TABLE CUSTOMER (
10+
ID BIGINT IDENTITY NOT NULL PRIMARY KEY ,
11+
VERSION BIGINT ,
12+
NAME VARCHAR(45) ,
13+
CREDIT DECIMAL(10,2)
14+
) ;
15+
16+
INSERT INTO CUSTOMER (ID, VERSION, NAME, CREDIT) VALUES (1, 0, 'customer1', 100000);
17+
INSERT INTO CUSTOMER (ID, VERSION, NAME, CREDIT) VALUES (2, 0, 'customer2', 100000);
18+
INSERT INTO CUSTOMER (ID, VERSION, NAME, CREDIT) VALUES (3, 0, 'customer3', 100000);
19+
INSERT INTO CUSTOMER (ID, VERSION, NAME, CREDIT) VALUES (4, 0, 'customer4', 100000);

spring-batch-samples/src/test/java/org/springframework/batch/sample/iosample/JdbcCursorFunctionalTests.java

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2006-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.batch.sample.jdbc;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.batch.core.BatchStatus;
22+
import org.springframework.batch.core.Job;
23+
import org.springframework.batch.core.JobExecution;
24+
import org.springframework.batch.core.JobParameters;
25+
import org.springframework.batch.core.launch.JobLauncher;
26+
import org.springframework.batch.test.JobLauncherTestUtils;
27+
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.context.ApplicationContext;
29+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
30+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
31+
32+
import static org.junit.jupiter.api.Assertions.assertEquals;
33+
34+
/**
35+
* @author Dan Garrette
36+
* @author Glenn Renfro
37+
* @author Mahmoud Ben Hassine
38+
* @since 2.0
39+
*/
40+
@SpringJUnitConfig(locations = { "/org/springframework/batch/sample/jdbc/job/jdbcCursor.xml",
41+
"/simple-job-launcher-context.xml", "/job-runner-context.xml" })
42+
class JdbcCursorFunctionalTests {
43+
44+
@Autowired
45+
private JobLauncherTestUtils jobLauncherTestUtils;
46+
47+
@Test
48+
void testLaunchJobWithXmlConfig() throws Exception {
49+
// when
50+
JobExecution jobExecution = this.jobLauncherTestUtils.launchJob();
51+
52+
// then
53+
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
54+
}
55+
56+
@Test
57+
public void testLaunchJobWithJavaConfig() throws Exception {
58+
// given
59+
ApplicationContext context = new AnnotationConfigApplicationContext(JdbcCursorReaderBatchWriterSampleJob.class);
60+
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
61+
Job job = context.getBean(Job.class);
62+
63+
// when
64+
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
65+
66+
// then
67+
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
68+
}
69+
70+
}

0 commit comments

Comments
 (0)