Skip to content
Exposed docs1.11

Exposed Spring Boot Batch Integration

Latest stable Based on Exposed release 1.11.0

Exposed range partitioning, keyset restart, and chunk writers inside Spring Boot’s Spring Batch runtime.

This module adds Exposed-aware Partitioner, ItemStreamReader, and ItemWriter implementations plus an overridable partition executor to a Spring Batch application. It relies on Spring Boot’s BatchAutoConfiguration for job infrastructure. Do not add @EnableBatchProcessing: in the supported Boot configuration it disables the Boot Batch auto-configuration this integration expects.

The adjacent lightweight runtime has a different ownership model:

Lightweight BatchStepRunner flow for comparison

Use this module when the application already uses Spring Batch jobs, steps, chunk commits, ExecutionContext, restart metadata, and partition execution, but wants Exposed to read and write application tables. Use Exposed Batch Utilities instead when a small coroutine runner with its own execution repository is sufficient.

Import the ecosystem BOM and omit the module version:

dependencies {
implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>"))
implementation("io.github.bluetape4k.exposed:bluetape4k-exposed-spring-boot-batch")
}

ExposedRangePartitioner reads the minimum and maximum of a monotonic Long key and writes minId and maxId into each partition’s ExecutionContext. ExposedKeysetItemReader restores those bounds plus lastKey, then reads column > lastKey AND column <= maxId ORDER BY column ASC LIMIT pageSize. Its update method saves lastKey, so Spring Batch persists progress at a committed chunk boundary.

The Exposed writers execute directly in the Spring Batch chunk transaction managed through SpringTransactionManager. They intentionally do not open a nested Exposed transaction {} block.

Keep Boot Batch auto-configuration enabled, define the job and chunk-oriented worker step, and attach an ExposedRangePartitioner to the manager step. Create a step-scoped ExposedKeysetItemReader for each partition and choose ExposedItemWriter, ExposedUpdateItemWriter, or ExposedUpsertItemWriter for the worker step.

spring:
batch:
job:
enabled: false # launch jobs explicitly when that matches the service lifecycle

Do not add @EnableBatchProcessing merely to make the job run; diagnose Boot Batch auto-configuration instead.

  • Partition a Column<Long> with ExposedRangePartitioner; use forEntityId for a LongIdTable.
  • Read a partition with ExposedKeysetItemReader; use its forEntityId factory for DAO ID tables.
  • Insert chunks with ExposedItemWriter, update each key with ExposedUpdateItemWriter, or use database-supported batch upsert through ExposedUpsertItemWriter.
  • Inject the bean named batchPartitionTaskExecutor into a partition handler, or provide a bean with that name to replace the default.
  • Configure jobs with the helpers in BatchJobExtensions.kt while leaving transaction ownership with Spring Batch.

Partition only on a unique, monotonic key whose range remains reasonably stable during a run. Keep gridSize, executor concurrency, database pool size, and downstream write capacity aligned. Use keyset ordering without gaps in the comparison semantics. Prefer upsert or another idempotent write when an operator may restart a job after uncertain external effects.

ExposedBatchAutoConfiguration runs after BatchAutoConfiguration and is conditional on Spring Batch Job. It contributes only ExposedBatchProperties and, when enabled and missing, batchPartitionTaskExecutor. The default is SimpleAsyncTaskExecutor with virtual threads enabled; an application-defined bean of the same name takes precedence.

bluetape4k.batch.executor.enabled=false disables the default executor. virtual-threads defaults to true; concurrency-limit defaults to twice the available processors; await-termination-seconds defaults to 30. These are executor limits, not database capacity guarantees. Set the reader pageSize, partition gridSize, Spring Batch chunk size, and datasource pool together from measurements.

  • Boot Batch infrastructure is missing after adding @EnableBatchProcessing: remove the annotation and let Boot auto-configure it.
  • A partition repeats or misses rows: verify a unique monotonic key, stable minId/maxId, and lastKey restoration.
  • Restart begins before expected data: only a committed chunk advances durable Spring Batch ExecutionContext; inspect the last committed step state.
  • Writer reports no Exposed transaction: verify the step uses the SpringTransactionManager connected to the same datasource and do not open an unrelated nested transaction.
  • Virtual-thread concurrency overwhelms the pool: reduce concurrency-limit, partition count, or chunk pressure; virtual threads do not create database connections.

Observe job and step status, partition name, minId, maxId, lastKey, read/write/skip counts, commit count, executor concurrency, pool acquisition, and chunk latency. On restart, compare the restored lastKey with the last committed business rows. An in-memory reader buffer is not durable; ExecutionContext is the restart authority.

Run the exact module tests:

Terminal window
./gradlew :bluetape4k-exposed-spring-boot-batch:test

Verify Boot auto-configuration without @EnableBatchProcessing, default and overridden executor beans, empty and uneven ranges, stable partition bounds, keyset restart from lastKey, chunk rollback, restart after a committed chunk, and insert/update/upsert writers participating in the existing chunk transaction without a nested transaction.

Compare Exposed Batch Utilities before choosing a runtime, then read transaction boundaries. Use the end-to-end and restart tests in this module as the executable Spring Batch contract.

Range partitioning assumes a Long-compatible, unique, monotonic key and is best when large inserts or deletes do not reshape the range during execution. lastKey records read progress at Spring Batch checkpoints; it does not make external side effects atomic. The default virtual-thread executor is optional and replaceable, and must still respect database pool limits.

These diagrams are loaded directly from README assets published with the 1.11.0 release and pinned to its immutable commit. They describe this manual’s released structure and runtime flows, not later Snapshot changes. Select a preview to open the SVG at the same release commit.

Spring Batch Exposed integration map

Release README: spring-boot/batch-exposed/README.md

Partitioned keyset restart flow

Release README: spring-boot/batch-exposed/README.md