A chunk step commits each successful group under its transaction manager; a later failing group rolls back its own writes.
Spring Batch chunks: a later failure does not erase an earlier commit
Observe the cut point
The source kit reads four receipt rows and writes two at a time. IDs 1 and 2 commit. The writer then throws after attempting ID 3 in the next group; the job is FAILED, the target table still has two rows, and ID 3 did not persist. A job-wide all-or-nothing import needs a different design. Transaction propagation does not merge distinct chunk commits.
Choose size for the resource
A larger chunk lowers commit frequency but retains more rows and holds locks longer. A smaller chunk spends more time committing and updating metadata. Measure with actual row size and database contention. The H2 check says nothing about an HTTP call or broker send made inside a writer: that remote side effect will not roll back with this database chunk.
Checked excerpt
return new StepBuilder("receiptImportStep", repository)
.<ReceiptRow, ReceiptRow>chunk(2)
.transactionManager(transactionManager)
.reader(receiptReader).writer(receiptWriter).build();Cost and verification
For n rows and chunk size c, expect roughly ceil(n/c) chunk commits plus repository work. Memory grows with c and the transformed item size. The isolated source-kit project checks the stated local behavior.
Common Mistakes
- Do not claim one job-wide rollback from a chunk step.
- Do not assume a remote side effect rolls back with the chunk.
- Do not choose a large chunk without measuring lock time.
Read next
Spring Batch job identity: a manifest ID defines restart versus a new run, Spring Batch writers: use a stable source key when a chunk is replayed, Spring transactional outbox: commit a receipt and event row together, Spring Batch chunk restart: know which receipts committed.
