ScrollableResults fetch size on a Hibernate 6 StatelessSession: hint or guarantee?
0 reputation · 13 Sept 2020, 07:08 UTC
0 reputation · 13 Sept 2020, 07:08 UTC
The goal is to stream a multi-million-row query in Hibernate ORM 6.x using ScrollableResults obtained from a StatelessSession, keeping heap usage flat while the JDBC driver batches rows according to a configured fetch size.
The uncertainty sits at the Hibernate–JDBC boundary. Query#setFetchSize() and hibernate.jdbc.fetch_size are documented as hints, and drivers treat them differently: PostgreSQL streams rows only when autocommit is off, while Oracle applies the hint per statement. StatelessSession holds no persistence context, so Hibernate itself should not buffer entities, but the documentation does not appear to guarantee that a per-query fetch size reaches Statement.setFetchSize() when the query runs as a scrollable cursor, or how ScrollMode.FORWARD_ONLY versus SCROLL_INSENSITIVE affects dialect-specific cursor creation.
Assume Hibernate 6.x with the PostgreSQL and Oracle dialects, read-only iteration, and one transaction held open for the whole scroll.
setFetchSize() on a scroll() call guaranteed to reach the JDBC statement in Hibernate 6, or can a dialect or wrapper override it?ScrollMode change the effective fetch size behavior between the PostgreSQL and Oracle dialects?Query.setFetchSize(int) is executed before the PreparedStatement is created. The Dialect’s prepareStatement helper passes that value unchanged to the JDBC driver. However, the value is a *hint*; Hibernate does not enforce it. A dialect or a JDBC wrapper can decide to ignore or adjust it (e.g. OracleDialect only applies it when the value is >0, PostgreSQLDialect applies it only when autocommit is false).ScrollMode.FORWARD_ONLY maps to ResultSet.TYPE_FORWARD_ONLY, ScrollMode.SCROLL_INSENSITIVE to ResultSet.TYPE_SCROLL_INSENSITIVE. The fetchSize hint is set on the PreparedStatement in both cases. SCROLL_INSENSITIVE can cause the driver to buffer rows, making the hint ineffective. org.hibernate.resource.jdbc.spi.StatementInspector API. Register a custom inspector that logs statement.getFetchSize() after preparation. Alternatively, wrap the DataSource with a proxy such as p6spy or FlexyPool and look for the last PreparedStatement.setFetchSize call before executeQuery(). The logged value is the hint Hibernate sent to the driver.StatelessSession.
ScrollResult sr = session.scroll("select …", ScrollMode.FORWARD_ONLY)
.setFetchSize(10_000);
configuration.addStatementInspector(new StatementInspector() {
@Override
public String inspect(String sql) { return sql; }
@Override
public void afterPrepare(PreparedStatement ps) {
System.out.println("Hibernate sent fetchSize=" + ps.getFetchSize());
}
});
autocommit truly disabled when you start the transaction?prepareThreshold or Oracle’s prefetch settings)?Hibernate 6 will pass the fetchSize hint to the JDBC driver, but it is not a guarantee of how the driver behaves. The scroll mode only influences the ResultSet type; fetchSize handling is dialect‑specific. Use a StatementInspector or a JDBC proxy to verify the value that actually reaches the driver.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.