From 9d8fe97de0179e221836891e3a0baf8b7e264b5a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 7 Nov 2013 23:58:15 +1300 Subject: [PATCH] Adjusted Fix for Issue 56 - Using findIterate with MySQL streams the entire result set at once. This makes the fix specific to the DatabasePlatform and findIterate() or findVisit(). --- .../config/dbplatform/DatabasePlatform.java | 24 +++++++++++++++++++ .../config/dbplatform/MySqlPlatform.java | 1 + .../ebeaninternal/server/query/CQuery.java | 11 +++++---- .../server/query/CQueryEngine.java | 5 +++- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java index 4ebad2729..54073bd84 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java @@ -63,6 +63,12 @@ public class DatabasePlatform { protected boolean selectCountWithAlias; + /** + * If set then use the FORWARD ONLY hint when creating ResultSets for + * findIterate() and findVisit(). + */ + protected boolean forwardOnlyHintOnFindIterate; + /** * Instantiates a new database platform. */ @@ -199,6 +205,24 @@ public class DatabasePlatform { return idInExpandedForm; } + /** + * Return true if the ResultSet TYPE_FORWARD_ONLY Hint should be used on + * findIterate() and findVisit() PreparedStatements. + *

+ * This specifically is required for MySql when processing large results. + *

+ */ + public boolean isForwardOnlyHintOnFindIterate() { + return forwardOnlyHintOnFindIterate; + } + + /** + * Set to true if the ResultSet TYPE_FORWARD_ONLY Hint should be used by default on findIterate PreparedStatements. + */ + public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) { + this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate; + } + /** * Return the DB identity/sequence features for this platform. * diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java index fba60277e..c89f06a6e 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java @@ -31,6 +31,7 @@ public class MySqlPlatform extends DatabasePlatform { this.openQuote = "`"; this.closeQuote = "`"; + this.forwardOnlyHintOnFindIterate = true; this.booleanDbType = Types.BIT; dbTypeMap.put(Types.BIT, new DbType("tinyint(1) default 0")); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java index 0ad5c619c..40ab36f72 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java @@ -346,8 +346,8 @@ public class CQuery implements DbReadContext, CancelableQuery { /** * Prepare bind and execute query with Forward only hints. */ - public boolean prepareBindExecuteQueryForwardOnly() throws SQLException { - return prepareBindExecuteQueryWithOption(true); + public boolean prepareBindExecuteQueryForwardOnly(boolean dbPlatformForwardOnlyHint) throws SQLException { + return prepareBindExecuteQueryWithOption(dbPlatformForwardOnlyHint); } /** @@ -357,7 +357,7 @@ public class CQuery implements DbReadContext, CancelableQuery { return prepareBindExecuteQueryWithOption(false); } - private boolean prepareBindExecuteQueryWithOption(boolean forward) throws SQLException { + private boolean prepareBindExecuteQueryWithOption(boolean forwardOnlyHint) throws SQLException { synchronized (this) { if (cancelled || query.isCancelled()) { @@ -371,8 +371,9 @@ public class CQuery implements DbReadContext, CancelableQuery { // prepare SpiTransaction t = request.getTransaction(); Connection conn = t.getInternalConnection(); - if (forward) { - // Hints required for mysql for large resultset processing (Issue 56) + + if (forwardOnlyHint) { + // Use forward only hints for large resultset processing (Issue 56, MySql specific) pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); } else { pstmt = conn.prepareStatement(sql); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java index 844f26af9..55757bb29 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java @@ -25,6 +25,8 @@ public class CQueryEngine { private static final Logger logger = LoggerFactory.getLogger(CQueryEngine.class); + private final DatabasePlatform dbPlatform; + private final CQueryBuilder queryBuilder; private final BackgroundExecutor backgroundExecutor; @@ -33,6 +35,7 @@ public class CQueryEngine { public CQueryEngine(DatabasePlatform dbPlatform, Binder binder, BackgroundExecutor backgroundExecutor) { + this.dbPlatform = dbPlatform; this.backgroundExecutor = backgroundExecutor; this.queryBuilder = new CQueryBuilder(backgroundExecutor, dbPlatform, binder); } @@ -122,7 +125,7 @@ public class CQueryEngine { try { - if (!cquery.prepareBindExecuteQueryForwardOnly()) { + if (!cquery.prepareBindExecuteQueryForwardOnly(dbPlatform.isForwardOnlyHintOnFindIterate())) { // query has been cancelled already logger.trace("Future fetch already cancelled"); return null;