It's very common to get first row of ResultSet or null
for empty ResultSet, for example JdbcStepExecutionDao::getLastStepExecution
from Spring Batch, see https://github.com/spring-projects/spring-batch/pull/4798 for background.
We should call Statement::setMaxRows
as hints (some legacy driver may not honer it) before executing, and only consume first row of the ResultSet.
Not sure about the return type, @Nullable T
or Optional<T>
is better?
If this proposal is accepted, then Optional<T> first()
should be added to JdbcClient
.
-
Why not
queryForList
? It will load all rows into memory. -
Why not
queryForObject
? It requires exactly one row, but the ResultSet may be empty, and there is no standard syntax to limit one row across all databases. -
Why not
queryForStream().findFirst()
? The result stream need be closed explicitly, andmaxRows
is set for wholeJdbcTemplate
, we need specific 1 only for this query.
Comment From: jhoeller
At this point, I prefer to leave JdbcTemplate
as-is in terms of first-class operations - but we could tweak its setMaxRows
behavior: skipping further rows during ResultSet processing once maxRows
has been reached, rather than just applying maxRows
to the JDBC Statement
. That way, queryForList
and co could be used for your purposes as-is, maybe in combination with a way to derive a JdbcTemplate
instance with different maxRows
but otherwise same settings.
Since JdbcClient
provides MappedQuerySpec.single/optional()
, it could automatically apply setMaxRows(1)
and make sure that it consumes one row from the ResultSet
for such an operation. Such limiting of retrieval does not hurt even if the result only contains a single row to begin with, so this seems to semantically fit into the existing single/optional()
methods. Assuming such limiting is in place for those, there does not seem to be a need for a separate first()
method.
Comment From: quaff
we could tweak its
setMaxRows
behavior: skipping further rows during ResultSet processing oncemaxRows
has been reached, rather than just applyingmaxRows
to the JDBCStatement
.
I created GH-34709 to address this part, please review.
Comment From: quaff
derive a
JdbcTemplate
instance with differentmaxRows
but otherwise same settings.
Do you mean add a method like this?
public JdbcTemplate withMaxRows(int maxRows) {
JdbcTemplate template = new JdbcTemplate(getDataSource());
template.setMaxRows(maxRows);
// copy other properties
return template;
}
It's a bit weird only maxRows
is treated specially.
IMHO, people used to reuse shared instance like auto-configured one by Spring Boot, instead of creating new JdbcTemplate
/JdbcClient
instances base on existing one only for different maxRows
.
Comment From: quaff
FYI, I created prototype to introduce new methods for JdbcClient
.
Comment From: quaff
FYI, I created prototype to introduce new methods for
JdbcClient
.
A better solution is introducing overloading variant for list methods to accept maxRows
, and add default first
methods, see prototype on another branch.
Comment From: quaff
A better solution is introducing overloading variant for list methods to accept
maxRows
, and add defaultfirst
methods, see prototype on another branch.
I'm tend to keep JdbcTemplate
as it is, in favor of introducing new methods to JdbcClient
, should I create an PR for review and open new issue or repurpose this issue? @jhoeller
Comment From: quaff
It should be closed by https://github.com/spring-projects/spring-framework/commit/842f582afce45c4018b5745d6534aa035de3b3b6