java 63 lines · 9 steps

How a chunk-based CSV import job works in Spring

A Spring Batch job reads customers from CSV, cleans each record, and writes them to the database in fault-tolerant chunks.

Explained by highlit
1@Configuration
2@EnableBatchProcessing
3public class CustomerImportJobConfig {
4 
5 @Bean
6 public FlatFileItemReader<CustomerCsvRecord> customerReader() {
7 return new FlatFileItemReaderBuilder<CustomerCsvRecord>()
8 .name("customerReader")
9 .resource(new ClassPathResource("customers.csv"))
10 .linesToSkip(1)
11 .delimited()
12 .names("externalId", "firstName", "lastName", "email", "signupDate")
13 .fieldSetMapper(fieldSet -> new CustomerCsvRecord(
14 fieldSet.readString("externalId"),
15 fieldSet.readString("firstName"),
16 fieldSet.readString("lastName"),
17 fieldSet.readString("email"),
18 fieldSet.readDate("signupDate", "yyyy-MM-dd")))
19 .build();
20 }
21 
22 @Bean
23 public ItemProcessor<CustomerCsvRecord, Customer> customerProcessor() {
24 return record -> {
25 if (record.email() == null || record.email().isBlank()) {
26 return null;
27 }
28 Customer customer = new Customer();
29 customer.setExternalId(record.externalId());
30 customer.setName(record.firstName().trim() + " " + record.lastName().trim());
31 customer.setEmail(record.email().toLowerCase());
32 customer.setSignupDate(record.signupDate());
33 return customer;
34 };
35 }
36 
37 @Bean
38 public JdbcBatchItemWriter<Customer> customerWriter(DataSource dataSource) {
39 return new JdbcBatchItemWriterBuilder<Customer>()
40 .dataSource(dataSource)
41 .sql("INSERT INTO customers (external_id, name, email, signup_date) "
42 + "VALUES (:externalId, :name, :email, :signupDate)")
43 .beanMapped()
44 .build();
45 }
46 
47 @Bean
48 public Step importCustomersStep(JobRepository jobRepository,
49 PlatformTransactionManager txManager,
50 FlatFileItemReader<CustomerCsvRecord> customerReader,
51 ItemProcessor<CustomerCsvRecord, Customer> customerProcessor,
52 JdbcBatchItemWriter<Customer> customerWriter) {
53 return new StepBuilder("importCustomersStep", jobRepository)
54 .<CustomerCsvRecord, Customer>chunk(200, txManager)
55 .reader(customerReader)
56 .processor(customerProcessor)
57 .writer(customerWriter)
58 .faultTolerant()
59 .skip(FlatFileParseException.class)
60 .skipLimit(25)
61 .build();
62 }
63}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Spring Batch's reader-processor-writer triad cleanly separates parsing, transformation, and persistence into swappable beans.
  2. 2Chunk-oriented steps commit work in fixed-size batches inside a transaction, balancing throughput against memory and rollback scope.
  3. 3A processor returning null filters an item out, and fault tolerance lets bad rows be skipped without aborting the whole job.

Related explainers

java
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
 

Transparent column encryption in Spring & JPA

encryption aes-gcm jpa-converter
Advanced 10 steps
java
package com.acme.billing.config;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;

Feature-flagged beans with Spring @ConditionalOnProperty

feature-flags conditional-beans strategy-pattern
Intermediate 5 steps
java
public static Map<String, String> parseCookieHeader(String header) {
    Map<String, String> cookies = new LinkedHashMap<>();
    if (header == null || header.isBlank()) {
        return cookies;

Parsing an HTTP Cookie header in Java

string-parsing http url-decoding
Intermediate 6 steps
java
public class TimedSocketReader {
 
    private static final int READ_TIMEOUT_MS = 5_000;
    private static final int CONNECT_TIMEOUT_MS = 3_000;

Reading a socket with connect and read timeouts

sockets timeouts io
Intermediate 8 steps
java
public final class EncodingDetector {
 
    public enum Encoding {
        UTF_8, UTF_16LE, UTF_16BE, UTF_32LE, UTF_32BE, ASCII, UNKNOWN

Detecting text encoding from raw bytes in Java

byte-manipulation encoding-detection bitwise-operations
Intermediate 8 steps
java
public final class ImportOrganizer {
 
    private static final Pattern IMPORT_LINE =
            Pattern.compile("^import\\s+(static\\s+)?([\\w.]+(?:\\.\\*)?)\\s*;\\s*$");

Sorting Java imports with a regex pass

regex sorting text-processing
Intermediate 8 steps

Share this explainer

Here's the card — post it anywhere.

How a chunk-based CSV import job works in Spring — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code