Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring Batch FlatFileItemReader: save state against an immutable source

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

A restartable file reader records position at committed checkpoints; that position is valid only while the source bytes and reader mapping stay compatible.

Know what the cursor proves

A settlement CSV reader may have consumed 47 records when a later write fails. The last committed chunk, not the last attempted read, defines safe restart progress. A named FlatFileItemReader can save its current item count in the StepExecution context and restore it on a new execution. That cursor does not certify the file contents. The source digest guard must reject replacement bytes under the same input identity.

Keep checkpoint and output aligned

Let the chunk transaction commit destination writes and repository state together where the infrastructure supports that boundary. A remote file or external API cannot join the database transaction; its writer needs idempotent keys so replay is safe. Turning off saveState can be reasonable for a one-shot disposable import, but it removes position-based restart. Idempotent writes remain useful even with a saved cursor because failures can occur between systems.

Exercise a real restart

Process a small immutable fixture, inject a failure during the second chunk, then terminate the process. Relaunch the same job instance with the same source version and inspect persisted StepExecution state. Compare the complete destination key set with the source: no gap, duplicate or silent skip. Test a changed file separately and require rejection before the reader resumes.

Implementation contract

Java
@Bean
@StepScope
FlatFileItemReader<ReceiptCsvRow> settlementReader(
        @Value("#{jobParameters['inputPath']}") String inputPath,
        LineMapper<ReceiptCsvRow> receiptLineMapper) {
    return new FlatFileItemReaderBuilder<ReceiptCsvRow>()
        .name("settlementCsvReader")
        .resource(new FileSystemResource(inputPath))
        .lineMapper(receiptLineMapper)
        .saveState(true)
        .build();
}

Cost and verification

Persisting a small cursor adds a repository update at checkpoints. A larger chunk reduces update frequency but increases work replayed after a failure and memory held before commit.

Common Mistakes

  • Do not restart from a line number in a replaced file.
  • Do not set saveState(false) while promising position-based restart.
  • Do not assume a saved cursor makes a non-idempotent external writer safe.

Read next

Spring Batch step scope: bind a reader to one execution, Spring Batch source digest: reject changed rows before a restart, Spring Batch writers: use a stable source key when a chunk is replayed, Spring Batch chunk restart: know which receipts committed, Spring Batch ExecutionContext keys: give each stream its own checkpoint.

spring
spring-batch
batch-flatfile-reader-checkpoint
Storage details