Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In Spring Batch, use CompositeItemReader when you need to read from multiple sources one after another. If your real problem is assembling parent and child records without an N+1 query pattern, a different, custom page-aware reader may fit better. These approaches share a name, but solve distinct problems.

What does “composite reader” mean in Spring Batch?

It can refer to either Spring Batch’s built-in CompositeItemReader or a custom extension that adds page-level processing to a paging reader. Choose based on the work to be done: sequentially consuming separate readers, or collecting related records for the parent items in each page.

Built-in source composition

Spring describes CompositeItemReader<T> as a reader that delegates to a list of ItemStreamReaders. It reads from those delegates in sequence, making it appropriate when a job should consume one source and then another. For example, a job could read from a primary database, a secondary database, and an archive file. See the Spring Batch API documentation for the class contract. A 2026 implementation guide describes this three-reader arrangement for combining systems in one job: implementation guide.

Custom page-aware relationship assembly

A custom composite paging reader addresses a different issue: fetching related records for a page of parent records in bulk. Hari Iyer’s 2019 DZone example extends JdbcPagingItemReader and invokes page-level logic after each page has been read. This is not a built-in Spring Batch feature. Read Iyer’s explanation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Sale
Spring Batch in Action
  • Used Book in Good Condition

How can a page-aware reader avoid N+1 queries?

Imagine a job that reads orders and also needs each order’s items. Joining orders to items in a paginated query can split the children of one order across page boundaries. Alternatively, querying for items in the processor once per order creates an N+1 pattern.

Iyer’s example uses two queries per page: one to fetch a page of order IDs and another to fetch all matching order items with an IN query ordered by order_id. With 100 orders in a page, the comparison is 2 queries rather than 101. These are illustrative query counts from the example, not benchmark results.

The trade-off is that application code must group or split the child records and attach them to their parent items. The order of results matters: fetch and assemble the records consistently so each child is associated with the intended parent.

How does the custom implementation work?

Iyer’s CompositeJdbcPagingItemReader<T> subclasses JdbcPagingItemReader<T> and accepts a PageProcessor<T> strategy with a void process(List<T> page) method. Its overridden doReadPage() first calls super.doReadPage(), then invokes the processor if the reader’s results list is non-empty. It also checks in afterPropertiesSet() that a page processor has been supplied.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

This approach depends on the paging reader’s protected results state and on when doReadPage() runs. Iyer identifies that dependency as implicit knowledge; treat the code as a version-sensitive extension, not a stable built-in API. Verify it against the Spring Batch version you deploy.

Should you use a cursor reader or a paging reader?

The choice depends on connection lifetime, memory, restart behavior, and how the query is structured. The following comparison reflects the 2026 implementation guide; details can vary with configuration and environment. 2026 guide.

Consideration Cursor reader Paging reader
Connection lifetime Holds a connection while reading. Releases connections between pages.
Memory Streams items with low memory use. Buffers a page of items.
Restart behavior Reopens a cursor and tracks the item count. Re-queries pages to resume progress.
Query pattern Reads through a cursor. Issues multiple queries, one for each page.

For relationship assembly, the custom page processor can reduce dependent child lookups from one per parent to one per page. The best option still depends on the workload: page size, query latency, connection use, and restart requirements all matter.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How should you choose and validate the design?

  • Use the built-in CompositeItemReader when the job should consume multiple readers sequentially.
  • Consider a page-aware custom reader when a page of parents needs a bulk lookup of related records.
  • Keep page sizes bounded, and ensure parent and child records are ordered and grouped consistently.
  • Test restart behavior and verify the custom extension against the Spring Batch version in production.
  • Measure query latency and connection use in your environment. Iyer reports better throughput from production use but publishes no percentage, workload details, or test method, so the example is not a performance guarantee.

As Iyer puts it, “efficient batch processing in the middle tier is mostly about reducing remote calls.” The practical lesson is to reduce repeated dependent lookups without confusing that optimization with sequentially combining sources.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.