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();