diff --git a/src/main/java/io/ebean/SqlUpdate.java b/src/main/java/io/ebean/SqlUpdate.java index 9884c095c..27e7be39e 100644 --- a/src/main/java/io/ebean/SqlUpdate.java +++ b/src/main/java/io/ebean/SqlUpdate.java @@ -98,6 +98,11 @@ public interface SqlUpdate { /** * Execute the update returning the number of rows modified. *
+ * Note that if the transaction has batch mode on then this update will use JDBC batch and may not execute until + * later - at commit time or a transaction flush. In this case this method returns -1 indicating that the + * update has been batched for later execution. + *
+ ** After you have executed the SqlUpdate you can bind new variables using * {@link #setParameter(String, Object)} etc and then execute the SqlUpdate * again. @@ -112,6 +117,11 @@ public interface SqlUpdate { */ int execute(); + /** + * Execute the statement now regardless of the JDBC batch mode of the transaction. + */ + int executeNow(); + /** * Execute when addBatch() has been used to batch multiple bind executions. * diff --git a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java index 1971b4b24..f1936cf94 100644 --- a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java +++ b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java @@ -312,4 +312,8 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader, */ int[] executeBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction); + /** + * Execute the sql update regardless of transaction batch mode. + */ + int executeNow(SpiSqlUpdate sqlUpdate); } diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 2a7c4e1cc..be4693ff7 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -2054,6 +2054,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return persister.executeSqlUpdate(updSql, t); } + @Override + public int executeNow(SpiSqlUpdate sqlUpdate) { + return persister.executeSqlUpdateNow(sqlUpdate, null); + } + @Override public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) { persister.addBatch(sqlUpdate, transaction); diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java index d9d4e6500..4ea9a06b0 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java @@ -133,6 +133,15 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { } } + @Override + public int executeNow() { + if (server != null) { + return server.executeNow(this); + } else { + throw new IllegalStateException("server is null?"); + } + } + @Override public int[] executeBatch() { if (server == null) { diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java index 6aa17970c..289592cbe 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java @@ -28,18 +28,23 @@ public final class PersistRequestUpdateSql extends PersistRequest { private boolean addBatch; - /** - * Create. - */ + private boolean forceNoBatch; + public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate, - SpiTransaction t, PersistExecute persistExecute) { + SpiTransaction t, PersistExecute persistExecute, boolean forceNoBatch) { super(server, t, persistExecute, sqlUpdate.getLabel()); this.type = Type.UPDATESQL; this.updateSql = sqlUpdate; + this.forceNoBatch = forceNoBatch; updateSql.reset(); } + public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate, + SpiTransaction t, PersistExecute persistExecute) { + this(server, sqlUpdate, t, persistExecute, false); + } + @Override public void profile(long offset, int flushCount) { profileBase(EVT_UPDATESQL, offset, (short)0, flushCount); @@ -60,7 +65,7 @@ public final class PersistRequestUpdateSql extends PersistRequest { @Override public boolean isBatchThisRequest() { - return addBatch || super.isBatchThisRequest(); + return !forceNoBatch && (addBatch || super.isBatchThisRequest()); } @Override diff --git a/src/main/java/io/ebeaninternal/server/core/Persister.java b/src/main/java/io/ebeaninternal/server/core/Persister.java index c64daaa4e..a1b9eedbe 100644 --- a/src/main/java/io/ebeaninternal/server/core/Persister.java +++ b/src/main/java/io/ebeaninternal/server/core/Persister.java @@ -74,10 +74,15 @@ public interface Persister { int executeOrmUpdate(Update> update, Transaction t); /** - * Execute the UpdateSql. + * Execute the SqlUpdate (taking into account transaction batch mode). */ int executeSqlUpdate(SqlUpdate update, Transaction t); + /** + * Execute the SqlUpdate now regardless of transaction batch mode. + */ + int executeSqlUpdateNow(SpiSqlUpdate update, Transaction t); + /** * Execute the CallableSql. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 884997f65..14f3b937b 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -150,6 +150,11 @@ public final class DefaultPersister implements Persister { return executeOrQueue(new PersistRequestUpdateSql(server, (SpiSqlUpdate) updSql, (SpiTransaction) t, persistExecute)); } + @Override + public int executeSqlUpdateNow(SpiSqlUpdate updSql, Transaction t) { + return executeOrQueue(new PersistRequestUpdateSql(server, updSql, (SpiTransaction) t, persistExecute, true)); + } + /** * Restore draft beans to match live beans given the query. */ diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index d52327463..2100f8d7c 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -854,6 +854,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return 0; } + @Override + public int executeNow(SpiSqlUpdate sqlUpdate) { + return 0; + } + @Override public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) { diff --git a/src/test/java/org/tests/update/TestSqlUpdateInTxn.java b/src/test/java/org/tests/update/TestSqlUpdateInTxn.java index e306e477d..673f72b01 100644 --- a/src/test/java/org/tests/update/TestSqlUpdateInTxn.java +++ b/src/test/java/org/tests/update/TestSqlUpdateInTxn.java @@ -3,6 +3,7 @@ package org.tests.update; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.SqlUpdate; +import io.ebean.Transaction; import io.ebean.meta.MetaTimedMetric; import org.junit.Assert; import org.junit.Test; @@ -38,6 +39,41 @@ public class TestSqlUpdateInTxn extends BaseTestCase { } } + @Test + public void testExecute_inTransaction_withBatch() { + + try (Transaction transaction = Ebean.beginTransaction()) { + transaction.setBatchMode(true); + + int row = Ebean.createSqlUpdate("update audit_log set description = description where id = ?") + .setParameter(1, 999999) + .execute(); + + // update statement using JDBC batch so not executed yet + assertThat(row).isEqualTo(-1); + + transaction.commit(); + } + + } + + @Test + public void testExecuteNow_inTransaction_withBatch() { + + try (Transaction transaction = Ebean.beginTransaction()) { + transaction.setBatchMode(true); + + int row = Ebean.createSqlUpdate("update audit_log set description = description where id = ?") + .setParameter(1, 999999) + .executeNow(); + + // update statement executed even though JDBC batch mode is on + assertThat(row).isEqualTo(0); + + transaction.commit(); + } + } + @Test public void testSqlUpdateWithWhitespace() {