skip to content

What does .noRollback(Exception.class) do on a fault-tolerant Spring Batch step, and when would you use it?

level: seniorimportance: should knowfreq 42%

answer

  1. noRollback = don't roll back for this exception type
  2. FaultTolerantStepBuilder.noRollback(Class)
  3. Best for processor validation exceptions
  4. Writer exceptions ALWAYS roll back
  5. Pair with skip() usually

basics

~20 s

noRollback tells the step that a given exception type should NOT trigger a transaction rollback. Use it when a processor throws a business/validation exception you want to handle (e.g. skip that item) without discarding the whole chunk's transaction. It applies to processor exceptions, not writer exceptions.

solid answer

~40 s

By default any exception thrown in a fault-tolerant step rolls back the chunk transaction. `FaultTolerantStepBuilder.noRollback(Class)` marks specific exception types as non-rollback-causing, so when they're thrown the transaction is NOT rolled back and the good work in the chunk can still commit. The classic case is a validation/business exception thrown inside the `ItemProcessor` that you treat as 'just skip this item' — there's no persisted state to undo, so paying the rollback + re-scan cost is wasteful. The important caveat: **noRollback is honored for exceptions from the processor, not from the ItemWriter** — a writer exception means data may already be in an inconsistent state within the transaction, so Batch always rolls back regardless of noRollback. It's configured on a fault-tolerant step and usually paired with skip() for the same type.

code

java · 20 lines
java
@Bean
public Step orderStep(JobRepository jobRepository,
                      PlatformTransactionManager txManager,
                      ItemReader<Order> reader,
                      ItemProcessor<Order, Order> validatingProcessor,
                      ItemWriter<Order> writer) {
    return new StepBuilder("orderStep", jobRepository)
            .<Order, Order>chunk(10, txManager)
            .reader(reader)
            .processor(validatingProcessor)
            .writer(writer)
            .faultTolerant()
            // A validation failure in the processor should skip the item...
            .skip(ValidationException.class)
            .skipLimit(50)
            // ...but NOT roll back the chunk transaction, since nothing
            // was written yet — the good items still commit.
            .noRollback(ValidationException.class)
            .build();
}

go deeper

for a junior

Knows noRollback stops a rollback for a chosen exception type.

for a middle

Uses it with skip() for processor validation and knows it needs faultTolerant().

for a senior

Articulates the writer-exception caveat and the orthogonality of noRollback vs skip vs retry.

for a principal

Weighs when avoiding rollback is a real optimization vs a correctness risk, given processor purity and transactional resource semantics.

## Default: everything rolls back On a fault-tolerant step, the default contract is conservative: **any** exception thrown anywhere in the chunk causes the enclosing transaction to roll back. That's safe, but it triggers the whole rollback + single-item rescan machinery even for exceptions where nothing was actually written and there's nothing to undo. ## What noRollback changes `.noRollback(Class<? extends Throwable> type)` on the `FaultTolerantStepBuilder` (you get one by calling `.faultTolerant()`) registers exception types that should **not** mark the transaction for rollback. When such an exception is thrown, Batch does not roll back the chunk's transaction; the items already successfully processed can still be committed, avoiding the expensive rollback-and-rescan. ## The canonical use case: processor validation The textbook scenario is an `ItemProcessor` that runs business validation and throws, say, a `ValidationException` for records that fail a rule, which you want to **skip** rather than fail the job over. Because that exception is raised during *processing* — before anything is written — there is no uncommitted output tied to it, so rolling back the whole chunk is pure overhead. You configure: ```java .faultTolerant() .skip(ValidationException.class) .skipLimit(50) .noRollback(ValidationException.class) ``` Now a `ValidationException` skips the offending item **without** rolling back the transaction for the rest of the chunk. ## The critical caveat: writers still roll back **noRollback does not protect exceptions thrown by the `ItemWriter`.** Once you're in the write phase, output may have been partially applied within the transaction, so Batch cannot safely leave that transaction to commit — it always rolls back on a writer exception, regardless of any noRollback registration. Treat noRollback as a **processor-phase** (and listener/read-phase) optimization. Reads are non-transactional anyway, so the interesting target is processor exceptions. ## Interaction with skip and retry - noRollback is about **whether to roll back**; skip is about **whether to discard the item and continue**; retry is about **re-attempting**. They're orthogonal knobs you often combine. Marking a type noRollback without also making it skippable means the exception still propagates (it just didn't roll back) — usually you want both. - If an exception type is retryable, rolling back is normally desirable so the retry starts clean; noRollback on a retryable type is unusual. ## Gotchas - Only meaningful on a **fault-tolerant** step; plain steps don't expose it. - Getting it wrong on writer exceptions gives a false sense of safety — the framework overrides you and rolls back anyway. - If your processor mutates shared/external state before throwing, noRollback means that mutation is NOT undone (there was no transactional undo for it anyway) — another reason processors should be side-effect-free.

  • If you add .noRollback(SomeException.class) but SomeException is thrown by the ItemWriter, will the transaction commit?
    No. noRollback is not honored for ItemWriter exceptions — the writer participates in the transaction and data may be partially applied, so Batch always rolls back on a writer exception regardless of noRollback.
  • Does noRollback by itself make an item be skipped?
    No. noRollback only prevents rollback for that exception type; whether the item is skipped/retried/propagated is governed separately by skip()/retry(). You typically combine noRollback with skip() for the same exception type.

saying these in an interview costs you the question

  • Believing noRollback prevents rollback even for ItemWriter exceptions
  • Thinking noRollback alone causes the item to be skipped
  • Assuming noRollback is available on a non-fault-tolerant step

context