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 a8b4b3e70..c5b4413fd 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java @@ -39,6 +39,12 @@ public class DatabasePlatform { COMMIT } + + /** + * Set to true for MySql, no other jdbc drivers need this workaround. + */ + protected boolean useExtraTransactionOnIterateSecondaryQueries; + /** * The behaviour used when ending a read only transaction at read committed isolation level. */ @@ -153,6 +159,17 @@ public class DatabasePlatform { return name; } + /** + * Return true if the JDBC driver does not allow additional queries to execute + * when a resultSet is being 'streamed' as is the case with findEach() etc. + *

+ * Honestly, this is a workaround for a stupid MySql JDBC driver limitation. + *

+ */ + public boolean useExtraTransactionOnIterateSecondaryQueries() { + return useExtraTransactionOnIterateSecondaryQueries; + } + /** * Return a DB Sequence based IdGenerator. * 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 111782421..e9e5becf0 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java @@ -20,6 +20,7 @@ public class MySqlPlatform extends DatabasePlatform { public MySqlPlatform() { super(); this.name = "mysql"; + this.useExtraTransactionOnIterateSecondaryQueries = true; this.likeClause = "like ? escape''"; this.selectCountWithAlias = true; this.dbEncrypt = new MySqlDbEncrypt(); diff --git a/src/main/java/com/avaje/ebeaninternal/api/LoadRequest.java b/src/main/java/com/avaje/ebeaninternal/api/LoadRequest.java index d5ed56b7a..92ec982d3 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/LoadRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/api/LoadRequest.java @@ -48,4 +48,11 @@ public abstract class LoadRequest { return transaction; } + /** + * Return true if the parent query is a findIterate() type query. + * So one of - findIterate(), findEach(), findEachWhile() or findVisit(). + */ + public boolean isParentFindIterate() { + return parentRequest != null && parentRequest.getQuery().getType() == SpiQuery.Type.ITERATE; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java index 92a95ea4e..c1d7ac784 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java @@ -51,6 +51,11 @@ public interface SpiQuery extends Query { */ BEAN, + /** + * Find iterate type query - findEach(), findIterate() etc. + */ + ITERATE, + /** * Find returning a List. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java index 4f9231540..48c0a0629 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java @@ -5,6 +5,7 @@ import java.util.List; import javax.persistence.EntityNotFoundException; +import com.avaje.ebeaninternal.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,11 +16,6 @@ import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.bean.EntityBeanIntercept; import com.avaje.ebean.bean.ObjectGraphNode; import com.avaje.ebean.bean.PersistenceContext; -import com.avaje.ebeaninternal.api.LoadBeanBuffer; -import com.avaje.ebeaninternal.api.LoadBeanRequest; -import com.avaje.ebeaninternal.api.LoadManyRequest; -import com.avaje.ebeaninternal.api.LoadManyBuffer; -import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.api.SpiQuery.Mode; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; @@ -36,8 +32,11 @@ public class DefaultBeanLoader { private final DefaultServer server; + private final boolean onIterateUseExtraTxn; + protected DefaultBeanLoader(DefaultServer server) { this.server = server; + this.onIterateUseExtraTxn = server.getDatabasePlatform().useExtraTransactionOnIterateSecondaryQueries(); } /** @@ -143,7 +142,17 @@ public class DefaultBeanLoader { query.select(many.getTargetIdProperty()); } - server.findList(query, loadRequest.getTransaction()); + if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) { + // MySql - we need a different transaction to execute the secondary query + SpiTransaction extraTxn = server.createQueryTransaction(); + try { + server.findList(query, extraTxn); + } finally { + extraTxn.end(); + } + } else { + server.findList(query, loadRequest.getTransaction()); + } // check for BeanCollection's that where never processed // in the +query or +lazy load due to no rows (predicates) @@ -332,7 +341,18 @@ public class DefaultBeanLoader { query.where().idIn(idList); } - List list = server.findList(query, loadRequest.getTransaction()); + List list; + if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) { + // MySql - we need a different transaction to execute the secondary query + SpiTransaction extraTxn = server.createQueryTransaction(); + try { + list = server.findList(query, extraTxn); + } finally { + extraTxn.end(); + } + } else { + list = server.findList(query, loadRequest.getTransaction()); + } if (loadRequest.isLoadCache()) { for (int i = 0; i < list.size(); i++) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index 905087580..e0b1ca6e9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -1318,7 +1318,7 @@ public final class DefaultServer implements SpiEbeanServer { public void findVisit(Query query, QueryResultVisitor visitor, Transaction t) { - SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); request.initTransIfRequired(); request.findVisit(visitor); @@ -1327,7 +1327,7 @@ public final class DefaultServer implements SpiEbeanServer { public void findEach(Query query, QueryEachConsumer consumer, Transaction t) { - SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); request.initTransIfRequired(); request.findEach(consumer); @@ -1336,7 +1336,7 @@ public final class DefaultServer implements SpiEbeanServer { public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction t) { - SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); request.initTransIfRequired(); request.findEachWhile(consumer); @@ -1345,7 +1345,7 @@ public final class DefaultServer implements SpiEbeanServer { public QueryIterator findIterate(Query query, Transaction t) { - SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); try { request.initTransIfRequired();