You have a Spring Batch step that reads a CSV and calls a REST API with no database at all. Which PlatformTransactionManager should the chunk use, and why?
answer
- chunk always needs a PlatformTransactionManager
- no DB => ResourcelessTransactionManager (no-op)
- begin/commit/rollback do nothing
- pair with in-memory JobRepository, no restart persistence
- no real rollback => make REST calls idempotent
basics
~10 sUse ResourcelessTransactionManager. Chunk steps require a PlatformTransactionManager, but with no database there is no real transactional resource to manage, so this no-op manager satisfies the API without touching a datasource.
solid answer
~40 sEvery chunk step needs a PlatformTransactionManager because the chunk boundary is transactional by design. But when the step touches no transactional resource — reading a file and calling a REST endpoint — there is nothing to commit or roll back. ResourcelessTransactionManager is a no-op implementation: begin/commit/rollback do essentially nothing. You pass it to StepBuilder.chunk(size, resourcelessTxManager) so the framework's transaction bookkeeping still runs (chunk cycles, retry scaffolding) without the cost or requirement of a JDBC transaction. A common companion is running the JobRepository in-memory (or with a Map-based/Resourceless setup) so job metadata itself does not need a database. Caveat: because it is a no-op, it gives no rollback safety — if your REST calls have side effects, chunk atomicity does not protect you, so make them idempotent.
code
java · 12 lines@Bean
public Step fileToApiStep(JobRepository jobRepository,
ItemReader<Record> csvReader,
ItemWriter<Record> apiWriter) {
// No datasource in this step -> a no-op transaction manager
// satisfies the chunk API without a real transaction.
return new StepBuilder("fileToApiStep", jobRepository)
.<Record, Record>chunk(100, new ResourcelessTransactionManager())
.reader(csvReader)
.writer(apiWriter) // posts to REST; make it idempotent!
.build();
}go deeper
Knows a no-DB chunk step still needs some transaction manager.
Names ResourcelessTransactionManager as the no-op choice for non-DB steps.
Explains it satisfies the required API without a resource and pairs with an in-memory JobRepository; notes no real rollback.
Weighs loss of restart persistence and mandates idempotent external effects since atomicity is illusory.
## The requirement A chunk-oriented step is transactional by construction — `StepBuilder.chunk(size, transactionManager)` **requires** a `PlatformTransactionManager`. The framework starts a transaction per chunk, drives the read-process-write cycle inside it, and commits. ## The problem for no-DB jobs Sometimes a step has **no transactional resource**: it reads a flat file and writes to a REST API, a non-transactional queue, or another file. There is no datasource to enroll. You still must supply *a* `PlatformTransactionManager` to satisfy the API. ## The answer: ResourcelessTransactionManager `org.springframework.batch.support.transaction.ResourcelessTransactionManager` (also mirrored as a no-op manager in Spring's core for similar cases) is a **no-op** `PlatformTransactionManager`. Its `getTransaction`, `commit`, and `rollback` do effectively nothing — there is no underlying resource to affect. It exists precisely so the framework's transactional scaffolding (chunk loop, retry/skip machinery which is built on transaction boundaries) can run without a real transaction. You wire it exactly like any other: ``` .chunk(100, new ResourcelessTransactionManager()) ``` ## Companion: in-memory / non-DB JobRepository If the whole job runs without a database, you also do not want the `JobRepository` writing metadata to a datasource. In modern Spring Batch you can back the `JobRepository` with a non-persistent store (e.g., a `ResourcelessJobRepository` / in-memory setup) so **nothing** requires a DB. The transaction manager for the repository and the step both being resourceless keeps the job fully in-memory. Trade-off: **no restart persistence** — if the JVM dies mid-job, metadata is gone and you cannot cleanly restart. ## Critical caveats - **No rollback safety.** Because begin/commit/rollback are no-ops, chunk atomicity is illusory here. If item 50 fails, the framework 'rolls back' the chunk transaction — but that does nothing to the REST calls already made. **Make external effects idempotent.** - **Do not use it with a real datasource** in the same step expecting rollback — you would silently lose transactional protection. Use `DataSourceTransactionManager` / `JpaTransactionManager` when a DB is involved. - It is for genuinely non-transactional steps, or tests, not a performance shortcut for DB jobs. ## When to use - File-to-file, file-to-REST, file-to-non-transactional-queue steps. - Lightweight/utility jobs and many unit/integration tests where a DB is overkill. ## Key classes - `ResourcelessTransactionManager` — the no-op `PlatformTransactionManager`. - `DataSourceTransactionManager` / `JpaTransactionManager` — what you use *instead* when a DB is present. - `JobRepository` — pair with an in-memory/resourceless variant for a fully DB-free job.
- Does using ResourcelessTransactionManager give you rollback if a chunk fails?No. It is a no-op — begin/commit/rollback do nothing. The chunk boundary still exists structurally, but there is no resource to undo, so any side effects (REST posts, file writes) already made are not reversed. Idempotency is on you.
- Why can't you just pass null instead of a transaction manager?The chunk StepBuilder API requires a non-null PlatformTransactionManager; the framework unconditionally drives a transaction per chunk. ResourcelessTransactionManager is the sanctioned way to say 'transactional scaffolding, but no real resource'.
saying these in an interview costs you the question
- Claiming ResourcelessTransactionManager still provides rollback
- Using it alongside a real datasource and expecting DB atomicity
- Thinking you can omit the transaction manager entirely for a no-DB step