Skip to content

GH-5470: Avoid nested query in JdbcStepExecutionDao.getLastStepExecution - #5480

Open
arimu1 wants to merge 2 commits into
spring-projects:mainfrom
arimu1:GH-5470
Open

GH-5470: Avoid nested query in JdbcStepExecutionDao.getLastStepExecution#5480
arimu1 wants to merge 2 commits into
spring-projects:mainfrom
arimu1:GH-5470

Conversation

@arimu1

@arimu1 arimu1 commented Aug 5, 2026

Copy link
Copy Markdown

Fixes #5470

JdbcStepExecutionDao.getLastStepExecution previously called
jobExecutionDao.getJobParameters (a second JDBC statement) while a
ResultSet opened with setMaxRows(1) was still active. On databases
that refuse multiple simultaneously open portals (notably CockroachDB),
that nested prepare fails and restarts break whenever a prior
StepExecution exists for the same job instance and step name.

Changes

  • Select only STEP_EXECUTION_ID for the “last step execution” lookup
  • Keep portable statement.setMaxRows(1) (no SQL LIMIT, which is not
    supported by all databases Spring Batch targets)
  • After that statement completes and is closed by JdbcTemplate, load
    the full StepExecution via getStepExecution(long)

This matches the sequential approach suggested in the issue and the
workaround of reading the id first then delegating to
getStepExecution(long).

Note: open PR #5133 still performs getJobExecution inside the open
ResultSet callback, so it does not address GH-5470.

Testing

  • JdbcStepExecutionDaoTests (6 tests, including new coverage for same-job
    and cross-job-execution “last step” selection)
  • ./mvnw -pl spring-batch-core -am test -Dtest=JdbcStepExecutionDaoTests
  • JDK: Eclipse Temurin 25 (project requires 17; NullAway on this branch needs 22+)

arimu1 added 2 commits August 5, 2026 22:07
Read the last step execution id with a completed statement first,
then load the full StepExecution. Nested queries while a row-limited
ResultSet is open break databases that disallow multiple active
portals (for example CockroachDB). Keep setMaxRows(1) for portability
instead of SQL LIMIT.

Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
Drop setMaxRows(1) on the last-step id lookup so the portal reaches
CommandComplete instead of PortalSuspended. Read only the first ordered
row in Java, then call getStepExecution(long). Avoid SQL LIMIT for
portability; document why default fetchSize keeps this safe.

Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
@arimu1

arimu1 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Follow-up for the portal-completion case called out in #5470:

Nesting alone was not enough. setMaxRows(1) can leave a suspended portal (PortalSuspended rather than CommandComplete) on pgjdbc-style wire protocol, so a subsequent prepare still fails on CockroachDB even after the Java ResultSet is closed.

This push:

  • drops statement.setMaxRows(1) on the id-only lookup
  • keeps portable ORDER BY SE.CREATE_TIME DESC, SE.STEP_EXECUTION_ID DESC (no SQL LIMIT)
  • reads only the first ordered row in Java, lets the statement complete, then loads via getStepExecution(long)
  • documents why default fetch size + first-row consumption is acceptable for large history

JdbcStepExecutionDaoTests: 6/6 pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JdbcStepExecutionDao.getLastStepExecution nests a query inside an open row-limited ResultSet, breaking every restart on CockroachDB

1 participant