Skip to content

Commit 31560b7

Browse files
committed
HHH-19653 logging for JDBC fetch size and query timeout
possible mitigation for Oracle fetch size issue
1 parent 1ec62b7 commit 31560b7

File tree

6 files changed

+90
-9
lines changed

6 files changed

+90
-9
lines changed

hibernate-core/src/main/java/org/hibernate/engine/jdbc/JdbcLogging.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,32 @@ public interface JdbcLogging extends BasicLogger {
152152
@Message(value = "Unable to roll back isolated connection on exception ", id = 100021)
153153
void unableToRollBackIsolatedConnection(@Cause Exception ignored);
154154

155+
@LogMessage(level = DEBUG)
156+
@Message(value = "Using default JDBC fetch size: %s", id = 100022)
157+
void usingFetchSize(int fetchSize);
158+
159+
@LogMessage(level = WARN)
160+
@Message(value = "Low default JDBC fetch size: %s (consider setting 'hibernate.jdbc.fetch_size')", id = 100023)
161+
void warnLowFetchSize(int fetchSize);
162+
163+
@LogMessage(level = TRACE)
164+
@Message(value = "JDBC fetch size: %s", id = 100024)
165+
void fetchSize(int fetchSize);
166+
167+
@LogMessage(level = DEBUG)
168+
@Message(value = "Low JDBC fetch size: %s (consider setting 'hibernate.jdbc.fetch_size')", id = 100025)
169+
void lowFetchSize(int fetchSize);
170+
171+
@LogMessage(level = TRACE)
172+
@Message(value = "Setting JDBC fetch size: %s", id = 100026)
173+
void settingFetchSize(int fetchSize);
174+
175+
@LogMessage(level = TRACE)
176+
@Message(value = "Setting JDBC query timeout: %s", id = 100027)
177+
void settingQueryTimeout(int timeout);
178+
155179
@LogMessage(level = WARN)
156-
@Message(value = "Called joinTransaction() on a non-JTA EntityManager (ignoring)", id = 100025)
180+
@Message(value = "Called joinTransaction() on a non-JTA EntityManager (ignoring)", id = 100030)
157181
void callingJoinTransactionOnNonJtaEntityManager();
158182

159183
@LogMessage(level = TRACE)

hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.sql.DatabaseMetaData;
99
import java.sql.ResultSet;
1010
import java.sql.SQLException;
11+
import java.sql.Statement;
1112
import java.util.Collections;
1213
import java.util.List;
1314
import java.util.stream.Collectors;
@@ -49,7 +50,7 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData
4950
private final String url;
5051
private final String driver;
5152
private final boolean jdbcMetadataAccessible;
52-
53+
private final int defaultFetchSize;
5354

5455
//Lazily initialized: loading all sequence information upfront has been
5556
//shown to be too slow in some cases. In this way we only load it
@@ -71,6 +72,7 @@ private ExtractedDatabaseMetaDataImpl(
7172
SQLStateType sqlStateType,
7273
int transactionIsolation,
7374
int defaultTransactionIsolation,
75+
int defaultFetchSize,
7476
String url,
7577
String driver,
7678
boolean jdbcMetadataIsAccessible) {
@@ -88,6 +90,7 @@ private ExtractedDatabaseMetaDataImpl(
8890
this.sqlStateType = sqlStateType;
8991
this.transactionIsolation = transactionIsolation;
9092
this.defaultTransactionIsolation = defaultTransactionIsolation;
93+
this.defaultFetchSize = defaultFetchSize;
9194
this.url = url;
9295
this.driver = driver;
9396
this.jdbcMetadataAccessible = jdbcMetadataIsAccessible;
@@ -168,6 +171,11 @@ public int getDefaultTransactionIsolation() {
168171
return defaultTransactionIsolation;
169172
}
170173

174+
@Override
175+
public int getDefaultFetchSize() {
176+
return defaultFetchSize;
177+
}
178+
171179
@Override
172180
public synchronized List<SequenceInformation> getSequenceInformationList() {
173181
if ( jdbcMetadataAccessible ) {
@@ -211,6 +219,7 @@ public static class Builder {
211219
private String driver;
212220
private int defaultTransactionIsolation;
213221
private int transactionIsolation;
222+
private int defaultFetchSize;
214223

215224
public Builder(JdbcEnvironment jdbcEnvironment, boolean jdbcMetadataIsAccessible, JdbcConnectionAccess connectionAccess) {
216225
this.jdbcEnvironment = jdbcEnvironment;
@@ -233,6 +242,12 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException {
233242
driver = databaseMetaData.getDriverName();
234243
defaultTransactionIsolation = databaseMetaData.getDefaultTransactionIsolation();
235244
transactionIsolation = databaseMetaData.getConnection().getTransactionIsolation();
245+
try ( Statement statement = databaseMetaData.getConnection().createStatement() ) {
246+
defaultFetchSize = statement.getFetchSize();
247+
}
248+
catch (SQLException sqle) {
249+
defaultFetchSize = -1;
250+
}
236251
return this;
237252
}
238253

@@ -302,6 +317,7 @@ public ExtractedDatabaseMetaDataImpl build() {
302317
sqlStateType,
303318
transactionIsolation,
304319
defaultTransactionIsolation,
320+
defaultFetchSize,
305321
url,
306322
driver,
307323
jdbcMetadataIsAccessible

hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.hibernate.boot.model.naming.Identifier;
1111
import org.hibernate.boot.registry.selector.spi.StrategySelector;
1212
import org.hibernate.cfg.AvailableSettings;
13+
import org.hibernate.cfg.JdbcSettings;
1314
import org.hibernate.dialect.Dialect;
1415
import org.hibernate.engine.config.spi.ConfigurationService;
1516
import org.hibernate.engine.config.spi.StandardConverters;
@@ -38,6 +39,7 @@
3839
import static org.hibernate.cfg.MappingSettings.DEFAULT_CATALOG;
3940
import static org.hibernate.cfg.MappingSettings.DEFAULT_SCHEMA;
4041
import static org.hibernate.engine.config.spi.StandardConverters.STRING;
42+
import static org.hibernate.engine.jdbc.JdbcLogging.JDBC_MESSAGE_LOGGER;
4143
import static org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl.makeLobCreatorBuilder;
4244

4345
/**
@@ -105,6 +107,8 @@ public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, fin
105107
new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport, dialect.getCatalogSeparator() );
106108

107109
lobCreatorBuilder = makeLobCreatorBuilder( dialect );
110+
111+
logJdbcFetchSize( extractedMetaDataSupport.getDefaultFetchSize(), cfgService );
108112
}
109113

110114
private static ConfigurationService configurationService(ServiceRegistryImplementor serviceRegistry) {
@@ -317,6 +321,8 @@ public JdbcEnvironmentImpl(
317321
new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport, databaseMetaData );
318322

319323
lobCreatorBuilder = makeLobCreatorBuilder( dialect, cfgService.getSettings(), databaseMetaData.getConnection() );
324+
325+
logJdbcFetchSize( extractedMetaDataSupport.getDefaultFetchSize(), cfgService );
320326
}
321327

322328
private static IdentifierHelper identifierHelper(
@@ -420,4 +426,14 @@ public LobCreatorBuilder getLobCreatorBuilder() {
420426
return lobCreatorBuilder;
421427
}
422428

429+
private static void logJdbcFetchSize(int defaultFetchSize, ConfigurationService cfgService) {
430+
if ( !cfgService.getSettings().containsKey( JdbcSettings.STATEMENT_FETCH_SIZE ) ) {
431+
if ( defaultFetchSize > 0 && defaultFetchSize < 100 ) {
432+
JDBC_MESSAGE_LOGGER.warnLowFetchSize( defaultFetchSize );
433+
}
434+
else {
435+
JDBC_MESSAGE_LOGGER.usingFetchSize( defaultFetchSize );
436+
}
437+
}
438+
}
423439
}

hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ public interface ExtractedDatabaseMetaData {
150150
*/
151151
int getDefaultTransactionIsolation();
152152

153+
/**
154+
* Retrieve the default JDBC {@link java.sql.Statement#getFetchSize fetch size}.
155+
*/
156+
int getDefaultFetchSize();
157+
153158
/**
154159
* Retrieve the list of {@code SequenceInformation} objects which describe the underlying database sequences.
155160
*

hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparerImpl.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
import org.checkerframework.checker.nullness.qual.Nullable;
2727

28+
import static org.hibernate.engine.jdbc.JdbcLogging.JDBC_MESSAGE_LOGGER;
29+
2830
/**
2931
* Standard implementation of {@link StatementPreparer}.
3032
*
@@ -141,7 +143,7 @@ public PreparedStatement prepareQueryStatement(
141143
final int resultSetType;
142144
if ( scrollMode != null && scrollMode != ScrollMode.FORWARD_ONLY ) {
143145
if ( !settings().isScrollableResultSetsEnabled() ) {
144-
throw new AssertionFailure("scrollable result sets are not enabled");
146+
throw new AssertionFailure( "Scrollable result sets are not enabled" );
145147
}
146148
resultSetType = scrollMode.toResultSetType();
147149
}
@@ -224,8 +226,21 @@ public void postProcess(PreparedStatement preparedStatement) throws SQLException
224226
}
225227

226228
private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
227-
if ( settings().getFetchSizeOrNull() != null ) {
228-
statement.setFetchSize( settings().getFetchSizeOrNull() );
229+
final Integer fetchSize = settings().getFetchSizeOrNull();
230+
if ( fetchSize != null ) {
231+
JDBC_MESSAGE_LOGGER.settingFetchSize( fetchSize );
232+
statement.setFetchSize( fetchSize );
233+
}
234+
else {
235+
if ( JDBC_MESSAGE_LOGGER.isDebugEnabled() ) {
236+
final int defaultFetchSize = statement.getFetchSize();
237+
if ( defaultFetchSize > 0 && defaultFetchSize < 100 ) {
238+
JDBC_MESSAGE_LOGGER.lowFetchSize( defaultFetchSize );
239+
}
240+
}
241+
else if ( JDBC_MESSAGE_LOGGER.isTraceEnabled() ) {
242+
JDBC_MESSAGE_LOGGER.fetchSize( statement.getFetchSize() );
243+
}
229244
}
230245
}
231246

hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
3737

3838
import static java.util.Collections.emptyMap;
39+
import static org.hibernate.engine.jdbc.JdbcLogging.JDBC_MESSAGE_LOGGER;
3940

4041
/**
4142
* @author Steve Ebersole
@@ -241,11 +242,15 @@ private void setQueryOptions(PreparedStatement preparedStatement) throws SQLExce
241242
final QueryOptions queryOptions = executionContext.getQueryOptions();
242243
// set options
243244
if ( queryOptions != null ) {
244-
if ( queryOptions.getFetchSize() != null ) {
245-
preparedStatement.setFetchSize( queryOptions.getFetchSize() );
245+
final Integer fetchSize = queryOptions.getFetchSize();
246+
if ( fetchSize != null ) {
247+
JDBC_MESSAGE_LOGGER.settingFetchSize( fetchSize );
248+
preparedStatement.setFetchSize( fetchSize );
246249
}
247-
if ( queryOptions.getTimeout() != null ) {
248-
preparedStatement.setQueryTimeout( queryOptions.getTimeout() );
250+
final Integer timeout = queryOptions.getTimeout();
251+
if ( timeout != null ) {
252+
JDBC_MESSAGE_LOGGER.settingQueryTimeout( timeout );
253+
preparedStatement.setQueryTimeout( timeout );
249254
}
250255
}
251256
}

0 commit comments

Comments
 (0)