Class TimeoutAwareQueryRunner
QueryRunner that applies a per-statement JDBC query timeout, computed against a
shared transaction deadline rather than a fixed value (D-10 -- Spring's approach: each
statement gets the time remaining in the transaction's budget, not a fresh full
allowance).
Overrides AbstractQueryRunner.prepareStatement(Connection, String) -- the one override point AbstractQueryRunner's own javadoc documents for
exactly this purpose ("Subclasses can override this method to provide special
PreparedStatement configuration if needed"), confirmed by reading
commons-dbutils-1.8.1-sources.jar. Every other QueryRunner behavior --
parameter binding, result-set handling, resource cleanup -- is untouched.
deadlineSupplier is read fresh on every statement, not captured once: the operator
holding this runner outlives any single transaction, so the deadline it should honor changes
across calls. A null result means "no timeout configured" -- no active transaction, or
@Transactional(timeout = 0) (the default) -- and Statement.setQueryTimeout(int)
is not called at all, leaving the statement at the driver's own default.
The floor. An already-exhausted budget produces MIN_QUERY_TIMEOUT_SECONDS
(currently 1), never 0 and never a negative number. In the JDBC contract,
setQueryTimeout(0) means "no limit" -- silently handing an exhausted budget an
unlimited timeout would be the opposite of what a timeout is for. A negative value is rejected
by the driver outright. Flooring at the smallest real limit is the only choice that fails fast
instead of either of those.
Deliberately does not attempt to cancel or interrupt a statement already in flight when its budget expires -- that would be a wall-clock bound on the surrounding method body, which REQUIREMENTS.md rules out as not implementable on plain JDBC (WIRE-14). The bound here is per-statement, by construction, applied before the statement is ever executed.
- Since:
- 6.3.0
- Author:
- wisdomme
-
Field Summary
FieldsModifier and TypeFieldDescriptionSupplies the active transaction's deadline as aSystem.nanoTime()value, ornullwhen no timeout is configured for the current statement (no active transaction, or a zero/negative@Transactional(timeout=)).(package private) static final intThe smallest query timeout, in seconds, this runner will ever apply.Fields inherited from class org.apache.commons.dbutils.AbstractQueryRunner
ds -
Constructor Summary
ConstructorsConstructorDescriptionTimeoutAwareQueryRunner(DataSource dataSource, Supplier<Long> deadlineSupplier) Creates a new timeout-aware query runner. -
Method Summary
Modifier and TypeMethodDescriptionprotected PreparedStatementprepareStatement(Connection conn, String sql) (package private) static intremainingSecondsFloored(long deadlineNanos) Converts aSystem.nanoTime()deadline into the whole seconds remaining, floored atMIN_QUERY_TIMEOUT_SECONDSso an exhausted or already-passed deadline still produces a real, enforced limit rather than0("no limit") or a negative value (which the JDBC driver rejects).Methods inherited from class org.apache.commons.dbutils.QueryRunner
batch, batch, execute, execute, execute, execute, insert, insert, insert, insert, insertBatch, insertBatch, query, query, query, query, query, query, query, query, update, update, update, update, update, updateMethods inherited from class org.apache.commons.dbutils.AbstractQueryRunner
close, close, close, closeQuietly, closeQuietly, closeQuietly, fillStatement, fillStatement, fillStatementWithBean, fillStatementWithBean, getDataSource, getParameterMetaData, isPmdKnownBroken, prepareCall, prepareConnection, prepareStatement, rethrow, wrap
-
Field Details
-
MIN_QUERY_TIMEOUT_SECONDS
static final int MIN_QUERY_TIMEOUT_SECONDSThe smallest query timeout, in seconds, this runner will ever apply.setQueryTimeout(0)means "no limit" in the JDBC contract, so an exhausted deadline must never round down to it -- 1 is the smallest value that still means "a real, enforced limit."- See Also:
-
deadlineSupplier
Supplies the active transaction's deadline as aSystem.nanoTime()value, ornullwhen no timeout is configured for the current statement (no active transaction, or a zero/negative@Transactional(timeout=)). Read fresh per statement -- see the class javadoc.
-
-
Constructor Details
-
TimeoutAwareQueryRunner
Creates a new timeout-aware query runner.- Parameters:
dataSource- the data source to use for connectionsdeadlineSupplier- supplies the current transaction's deadline (System.nanoTime()value), ornullwhen no timeout applies
-
-
Method Details
-
prepareStatement
- Overrides:
prepareStatementin classorg.apache.commons.dbutils.AbstractQueryRunner- Throws:
SQLException
-
remainingSecondsFloored
static int remainingSecondsFloored(long deadlineNanos) Converts aSystem.nanoTime()deadline into the whole seconds remaining, floored atMIN_QUERY_TIMEOUT_SECONDSso an exhausted or already-passed deadline still produces a real, enforced limit rather than0("no limit") or a negative value (which the JDBC driver rejects).Package-visible (not
private) soAbstractRelationalDataOperator's two directPreparedStatementcall sites --insertAll/updateAll, which bypassQueryRunnerentirely -- apply the identical floor this class does, rather than a second, potentially-diverging copy of the same arithmetic.- Parameters:
deadlineNanos- the deadline, as aSystem.nanoTime()value- Returns:
- the query timeout to apply, in seconds, always
>= MIN_QUERY_TIMEOUT_SECONDS
-