#1394 #1395 - ENH: Add addBatch() and executeBatch() to SqlUpdate ... alternative to changing transaction batch mode enhancement

ENH: Add merge() API (using default merge options) to EbeanServer, Ebean and BeanRepository enhancement
This commit is contained in:
rob bygrave
2018-05-30 03:31:32 +12:00
parent d8e67d09a9
commit af030e3da4
23 changed files with 484 additions and 32 deletions
@@ -167,6 +167,30 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
return db().deletePermanent(bean);
}
/**
* Merge this entity using the default merge options.
* <p>
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#merge(Object)
*/
public void merge(T bean) {
db().merge(bean);
}
/**
* Merge this entity using the specified merge options.
* <p>
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#merge(Object, MergeOptions)
*/
public void merge(T bean, MergeOptions options) {
db().merge(bean, options);
}
/**
* Refreshes this entity from the database.
*
+9
View File
@@ -638,6 +638,15 @@ public final class Ebean {
serverMgr.getDefaultServer().updateAll(beans);
}
/**
* Merge the bean using the default merge options.
*
* @param bean The bean to merge
*/
public static void merge(Object bean) {
serverMgr.getDefaultServer().merge(bean);
}
/**
* Merge the bean using the given merge options.
*
+7
View File
@@ -1628,6 +1628,13 @@ public interface EbeanServer {
*/
void updateAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Merge the bean using the default merge options (no paths specified, default delete).
*
* @param bean The bean to merge
*/
void merge(Object bean);
/**
* Merge the bean using the given merge options.
*
@@ -8,11 +8,20 @@ import java.util.Set;
*/
public class MergeOptionsBuilder {
private static final MOptions DEFAULT_OPTIONS = new MOptions();
private Set<String> paths = new LinkedHashSet<>();
private boolean clientGeneratedIds;
private boolean deletePermanent = true;
private boolean deletePermanent;
/**
* Return the default options.
*/
public static MergeOptions defaultOptions() {
return DEFAULT_OPTIONS;
}
/**
* Add a path that will included in the merge.
@@ -57,6 +66,12 @@ public class MergeOptionsBuilder {
private final boolean deletePermanent;
private final Set<String> paths;
private MOptions(){
this.clientGeneratedIds = false;
this.paths = new LinkedHashSet<>();
this.deletePermanent = false;
}
private MOptions(Set<String> paths, boolean clientGeneratedIds, boolean deletePermanent) {
this.paths = paths;
this.clientGeneratedIds = clientGeneratedIds;
+48 -7
View File
@@ -19,15 +19,17 @@ package io.ebean;
* <p>
* <pre>{@code
*
* // example that uses 'named' parameters
* String s = "UPDATE f_topic set post_count = :count where id = :id";
* SqlUpdate update = Ebean.createSqlUpdate(s);
* update.setParameter("id", 1);
* update.setParameter("count", 50);
* // example that uses 'named' parameters
*
* int modifiedCount = Ebean.execute(update);
* String s = "UPDATE f_topic set post_count = :count where id = :id";
*
* String msg = "There were " + modifiedCount + " rows updated";
* SqlUpdate update = Ebean.createSqlUpdate(s);
* update.setParameter("id", 1);
* update.setParameter("count", 50);
*
* int modifiedCount = update.execute();
*
* String msg = "There were " + modifiedCount + " rows updated";
*
* }</pre>
* <p>
@@ -57,6 +59,33 @@ package io.ebean;
*
* txn.commit();
* }
* }</pre>
* <p>
* An alternative to the batch mode on the transaction is to use addBatch() and executeBatch() like:
* </p>
* <pre>{@code
*
* try (Transaction txn = Ebean.beginTransaction()) {
*
* insert.setNextParameter(10000);
* insert.setNextParameter("hello");
* insert.setNextParameter("rob");
* insert.addBatch();
*
* insert.setNextParameter(10001);
* insert.setNextParameter("goodbye");
* insert.setNextParameter("rob");
* insert.addBatch();
*
* insert.setNextParameter(10002);
* insert.setNextParameter("chow");
* insert.setNextParameter("bob");
* insert.addBatch();
*
* int[] rows = insert.executeBatch();
*
* txn.commit();
* }
*
* }</pre>
*
@@ -83,6 +112,18 @@ public interface SqlUpdate {
*/
int execute();
/**
* Execute when addBatch() has been used to batch multiple bind executions.
*
* @return The row counts for each of the batched statements.
*/
int[] executeBatch();
/**
* Add the statement to batch processing to then later execute via executeBatch().
*/
void addBatch();
/**
* Return the generated key value.
*/
@@ -268,4 +268,15 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* Return true if a row for the bean type and id exists.
*/
boolean exists(Class<?> beanType, Object beanId, Transaction transaction);
/**
* Add to JDBC batch for later execution.
*/
void addBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction);
/**
* Execute the batched statement.
*/
int[] executeBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction);
}
@@ -13,6 +13,7 @@ import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.MergeOptions;
import io.ebean.MergeOptionsBuilder;
import io.ebean.PagedList;
import io.ebean.PersistenceContextScope;
import io.ebean.ProfileLocation;
@@ -65,6 +66,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiJsonContext;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiTransactionManager;
import io.ebeaninternal.api.TransactionEventTable;
@@ -919,6 +921,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return new DefaultUpdateQuery<>(createQuery(beanType));
}
@Override
public void merge(Object bean) {
merge(bean, MergeOptionsBuilder.defaultOptions(), null);
}
@Override
public void merge(Object bean, MergeOptions options) {
merge(bean, options, null);
@@ -1961,6 +1968,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return persister.executeSqlUpdate(updSql, t);
}
@Override
public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
persister.addBatch(sqlUpdate, transaction);
}
@Override
public int[] executeBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
return persister.executeBatch(sqlUpdate, transaction);
}
/**
* Execute the updateSql.
*/
@@ -1,11 +1,12 @@
package io.ebeaninternal.server.core;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.SqlUpdate;
import io.ebean.Update;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import java.io.Serializable;
@@ -26,7 +27,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
private static final long serialVersionUID = -6493829438421253102L;
private transient final EbeanServer server;
private transient final SpiEbeanServer server;
/**
* The parameters used to bind to the sql.
@@ -69,6 +70,16 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
private Object generatedKey;
/**
* Set when batching explicitly used.
*/
private boolean batched;
/**
* Transaction used for addBatch() executeBatch() processing.
*/
private transient SpiTransaction transaction;
/**
* Create with server sql and bindParams object.
* <p>
@@ -76,7 +87,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
* same time.
* </p>
*/
public DefaultSqlUpdate(EbeanServer server, String sql, BindParams bindParams) {
public DefaultSqlUpdate(SpiEbeanServer server, String sql, BindParams bindParams) {
this.server = server;
this.sql = sql;
this.bindParams = bindParams;
@@ -86,7 +97,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
* Create with a specific server. This means you can use the
* SqlUpdate.execute() method.
*/
public DefaultSqlUpdate(EbeanServer server, String sql) {
public DefaultSqlUpdate(SpiEbeanServer server, String sql) {
this(server, sql, new BindParams());
}
@@ -111,6 +122,10 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
@Override
public int execute() {
if (server != null) {
if (batched) {
server.executeBatch(this, transaction);
return -1;
}
return server.execute(this);
} else {
// Hopefully this doesn't catch anyone out...
@@ -118,6 +133,34 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
}
}
@Override
public int[] executeBatch() {
if (server == null) {
throw new IllegalStateException("No EbeanServer set?");
}
if (!batched) {
throw new IllegalStateException("No prior addBatch() called?");
}
return server.executeBatch(this, transaction);
}
@Override
public void addBatch() {
if (server == null) {
throw new IllegalStateException("No EbeanServer set?");
}
if (transaction == null) {
transaction = server.currentServerTransaction();
if (transaction == null) {
throw new IllegalStateException("No current transaction? Must have a transaction to use addBatch()");
}
}
batched = true;
server.addBatch(this, transaction);
}
@Override
public Object getGeneratedKey() {
return generatedKey;
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.core;
import io.ebean.SqlUpdate;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
@@ -27,15 +26,17 @@ public final class PersistRequestUpdateSql extends PersistRequest {
private String description;
private boolean addBatch;
/**
* Create.
*/
public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate sqlUpdate,
public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
SpiTransaction t, PersistExecute persistExecute) {
super(server, t, persistExecute, sqlUpdate.getLabel());
this.type = Type.UPDATESQL;
this.updateSql = (SpiSqlUpdate) sqlUpdate;
this.updateSql = sqlUpdate;
updateSql.reset();
}
@@ -44,11 +45,24 @@ public final class PersistRequestUpdateSql extends PersistRequest {
profileBase(EVT_UPDATESQL, offset, (short)0, flushCount);
}
/**
* Add this statement to JDBC batch for later execution.
*/
public int addBatch() {
this.addBatch = true;
return executeOrQueue();
}
@Override
public int executeNow() {
return persistExecute.executeSqlUpdate(this);
}
@Override
public boolean isBatchThisRequest() {
return addBatch || super.isBatchThisRequest();
}
@Override
public int executeOrQueue() {
return executeStatement();
@@ -8,6 +8,7 @@ import io.ebean.Transaction;
import io.ebean.Update;
import io.ebean.bean.EntityBean;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -91,4 +92,14 @@ public interface Persister {
* Visit the metrics.
*/
void visitMetrics(MetricVisitor visitor);
/**
* Add the statement to JDBC batch for later execution via executeBatch.
*/
void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
/**
* Execute the associated batched statement.
*/
int[] executeBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
}
@@ -637,9 +637,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
public void setEbeanServer(SpiEbeanServer ebeanServer) {
this.ebeanServer = ebeanServer;
for (BeanPropertyAssocMany<?> aPropertiesMany : propertiesMany) {
for (BeanPropertyAssocMany<?> assocMany : propertiesMany) {
// used for creating lazy loading lists etc
aPropertiesMany.setLoader(ebeanServer);
assocMany.setEbeanServer(ebeanServer);
}
}
@@ -7,10 +7,10 @@ import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebean.bean.BeanCollectionAdd;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.text.PathProperties;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.json.SpiJsonReader;
@@ -50,6 +50,8 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
private final String intersectionPublishTable;
private final String intersectionDraftTable;
private IntersectionTable intersectionTable;
/**
* For ManyToMany this is the Inverse join used to build reference queries.
*/
@@ -352,10 +354,30 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
* Set the lazy load server to help create reference collections (that lazy
* load on demand).
*/
public void setLoader(BeanCollectionLoader loader) {
public void setEbeanServer(SpiEbeanServer server) {
if (help != null) {
help.setLoader(loader);
help.setLoader(server);
}
if (manyToMany) {
intersectionTable = initIntersectionTable();
}
}
private IntersectionTable initIntersectionTable() {
IntersectionBuilder row = new IntersectionBuilder(intersectionPublishTable, intersectionDraftTable);
for (ExportedProperty exportedProperty : exportedProperties) {
row.addColumn(exportedProperty.getForeignDbColumn());
}
importedId.buildImport(row);
return row.build();
}
/**
* Return the intersection table helper.
*/
public IntersectionTable intersectionTable() {
return intersectionTable;
}
/**
@@ -755,6 +777,20 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
return intersectionDraftTable != null && !intersectionDraftTable.equals(intersectionPublishTable);
}
/**
* Bind the two side of a many to many to the given SqlUpdate.
*/
public void intersectionBind(SqlUpdate sql, EntityBean parentBean, EntityBean other) {
if (embeddedExportedProperties) {
BeanProperty idProp = descriptor.getIdProperty();
parentBean = (EntityBean) idProp.getValue(parentBean);
}
for (ExportedProperty exportedProperty : exportedProperties) {
sql.setNextParameter(exportedProperty.getValue(parentBean));
}
importedId.bindImport(sql, other);
}
private void buildExport(IntersectionRow row, EntityBean parentBean) {
if (embeddedExportedProperties) {
@@ -0,0 +1,85 @@
package io.ebeaninternal.server.deploy;
import java.util.ArrayList;
import java.util.List;
/**
* Helper to build IntersectionTable.
*/
public class IntersectionBuilder {
private final String publishTable;
private final String draftTable;
private final List<String> columns = new ArrayList<>();
IntersectionBuilder(String publishTable, String draftTable) {
this.publishTable = publishTable;
this.draftTable = draftTable;
}
public void addColumn(String column) {
columns.add(column);
}
public IntersectionTable build() {
String insertSql = insertSql(publishTable);
String deleteSql = deleteSql(publishTable);
String draftInsertSql;
String draftDeleteSql;
if (publishTable.equals(draftTable)) {
draftInsertSql = insertSql;
draftDeleteSql = deleteSql;
} else {
draftInsertSql = insertSql(draftTable);
draftDeleteSql = deleteSql(draftTable);
}
return new IntersectionTable(insertSql, deleteSql, draftInsertSql, draftDeleteSql);
}
private String insertSql(String tableName) {
StringBuilder sb = new StringBuilder();
sb.append("insert into ").append(tableName).append(" (");
int count = 0;
for (String column : columns) {
if (count++ > 0) {
sb.append(", ");
}
sb.append(column);
}
sb.append(") values (");
for (int i = 0; i < count; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append("?");
}
sb.append(")");
return sb.toString();
}
private String deleteSql(String tableName) {
StringBuilder sb = new StringBuilder();
sb.append("delete from ").append(tableName);
sb.append(" where ");
int count = 0;
for (String column : columns) {
if (count++ > 0) {
sb.append(" and ");
}
sb.append(column);
sb.append(" = ?");
}
return sb.toString();
}
}
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.EbeanServer;
import io.ebean.SqlUpdate;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.expression.DefaultExpressionRequest;
import io.ebeaninternal.server.expression.IdInExpression;
@@ -22,12 +22,12 @@ public class IntersectionRow {
private List<Object> excludeIds;
private BeanDescriptor<?> excludeDescriptor;
public IntersectionRow(String tableName, BeanDescriptor<?> targetDescriptor) {
IntersectionRow(String tableName, BeanDescriptor<?> targetDescriptor) {
this.tableName = tableName;
this.targetDescriptor = targetDescriptor;
}
public IntersectionRow(String tableName) {
IntersectionRow(String tableName) {
this.tableName = tableName;
this.targetDescriptor = null;
}
@@ -35,7 +35,7 @@ public class IntersectionRow {
/**
* Set Id's to exclude. This is for deleting non-attached detail Id's.
*/
public void setExcludeIds(List<Object> excludeIds, BeanDescriptor<?> excludeDescriptor) {
void setExcludeIds(List<Object> excludeIds, BeanDescriptor<?> excludeDescriptor) {
this.excludeIds = excludeIds;
this.excludeDescriptor = excludeDescriptor;
}
@@ -44,7 +44,7 @@ public class IntersectionRow {
values.put(key, value);
}
public SqlUpdate createInsert(EbeanServer server) {
public SqlUpdate createInsert(SpiEbeanServer server) {
BindParams bindParams = new BindParams();
@@ -72,7 +72,7 @@ public class IntersectionRow {
return new DefaultSqlUpdate(server, sb.toString(), bindParams);
}
public SqlUpdate createDelete(EbeanServer server, boolean softDelete) {
public SqlUpdate createDelete(SpiEbeanServer server, boolean softDelete) {
BindParams bindParams = new BindParams();
@@ -107,7 +107,7 @@ public class IntersectionRow {
return new DefaultSqlUpdate(server, sb.toString(), bindParams);
}
public SqlUpdate createDeleteChildren(EbeanServer server) {
public SqlUpdate createDeleteChildren(SpiEbeanServer server) {
BindParams bindParams = new BindParams();
@@ -0,0 +1,34 @@
package io.ebeaninternal.server.deploy;
import io.ebean.EbeanServer;
import io.ebean.SqlUpdate;
public class IntersectionTable {
private final String insertSql;
private final String deleteSql;
private final String draftInsertSql;
private final String draftDeleteSql;
IntersectionTable(String insertSql, String deleteSql, String draftInsertSql, String draftDeleteSql) {
this.insertSql = insertSql;
this.deleteSql = deleteSql;
this.draftInsertSql = draftInsertSql;
this.draftDeleteSql = draftDeleteSql;
}
/**
* Return a SqlUpdate for inserting into the intersection table.
*/
public SqlUpdate insert(EbeanServer server, boolean draft) {
return server.createSqlUpdate(draft ? draftInsertSql : insertSql);
}
/**
* Return a SqlUpdate for deleting from the intersection table.
*/
public SqlUpdate delete(EbeanServer server, boolean draft) {
return server.createSqlUpdate(draft ? draftDeleteSql : deleteSql);
}
}
@@ -4,6 +4,7 @@ import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.IntersectionBuilder;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
@@ -66,4 +67,14 @@ public interface ImportedId {
* Return the set importedId clause.
*/
String importedIdClause();
/**
* Add DB columns to the intersection builder.
*/
void buildImport(IntersectionBuilder row);
/**
* Bind values to the intersection SqlUpdate.
*/
void bindImport(SqlUpdate sql, EntityBean other);
}
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.IntersectionBuilder;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
@@ -130,15 +131,31 @@ public class ImportedIdEmbedded implements ImportedId {
EntityBean embeddedId = (EntityBean) foreignAssocOne.getValue(other);
if (embeddedId == null) {
String msg = "Foreign Key value null?";
throw new PersistenceException(msg);
throw new PersistenceException("Foreign Key value null?");
}
for (ImportedIdSimple anImported : imported) {
Object scalarValue = anImported.foreignProperty.getValue(embeddedId);
row.put(anImported.localDbColumn, scalarValue);
}
}
@Override
public void buildImport(IntersectionBuilder row) {
for (ImportedIdSimple importedScalar : imported) {
row.addColumn(importedScalar.localDbColumn);
}
}
@Override
public void bindImport(SqlUpdate sql, EntityBean other) {
EntityBean embeddedId = (EntityBean) foreignAssocOne.getValue(other);
if (embeddedId == null) {
throw new PersistenceException("Foreign Key value null?");
}
for (ImportedIdSimple anImported : imported) {
Object scalarValue = anImported.foreignProperty.getValue(embeddedId);
sql.setNextParameter(scalarValue);
}
}
/**
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.deploy.BeanFkeyProperty;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.IntersectionBuilder;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
@@ -98,6 +99,20 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
return foreignProperty.getValue(bean);
}
@Override
public void buildImport(IntersectionBuilder row) {
row.addColumn(localDbColumn);
}
@Override
public void bindImport(SqlUpdate sql, EntityBean other) {
Object value = getIdValue(other);
if (value == null) {
throw new PersistenceException("Foreign Key value null?");
}
sql.setNextParameter(value);
}
@Override
public void buildImport(IntersectionRow row, EntityBean other) {
@@ -6,6 +6,7 @@ import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -357,4 +358,11 @@ public final class BatchControl {
private BatchedBeanHolder[] getBeanHolderArray() {
return beanHoldMap.values().toArray(new BatchedBeanHolder[beanHoldMap.size()]);
}
/**
* Execute a batched statement.
*/
public int[] execute(String key, boolean getGeneratedKeys) throws SQLException {
return pstmtHolder.execute(key, getGeneratedKeys);
}
}
@@ -38,6 +38,8 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
private long profileStart;
private int[] results;
/**
* Create with a given statement.
*/
@@ -116,7 +118,7 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
private void executeAndCheckRowCounts() throws SQLException {
int[] results = pstmt.executeBatch();
results = pstmt.executeBatch();
if (results.length != list.size()) {
String s = "results array error " + results.length + " " + list.size();
throw new SQLException(s);
@@ -140,4 +142,10 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
}
}
/**
* Return the execution results (row counts).
*/
public int[] getResults() {
return results;
}
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.persist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedHashMap;
@@ -73,6 +74,19 @@ public class BatchedPstmtHolder {
return stmtMap.isEmpty();
}
/**
* Execute one of the batched statements returning the row counts.
*/
public int[] execute(String key, boolean getGeneratedKeys) throws SQLException {
BatchedPstmt batchedPstmt = stmtMap.remove(key);
if (batchedPstmt == null) {
throw new PersistenceException("No batched statement found for key " + key);
}
batchedPstmt.executeBatch(getGeneratedKeys);
return batchedPstmt.getResults();
}
/**
* Execute all batched PreparedStatements.
*
@@ -13,6 +13,7 @@ import io.ebean.bean.PersistenceContext;
import io.ebean.event.BeanPersistController;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiUpdate;
import io.ebeaninternal.server.core.Message;
@@ -34,6 +35,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -124,13 +126,28 @@ public final class DefaultPersister implements Persister {
}
}
@Override
public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
new PersistRequestUpdateSql(server, sqlUpdate, transaction, persistExecute).addBatch();
}
@Override
public int[] executeBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
BatchControl batchControl = transaction.getBatchControl();
try {
return batchControl.execute(sqlUpdate.getSql(), sqlUpdate.isGetGeneratedKeys());
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
/**
* Execute the updateSql.
*/
@Override
public int executeSqlUpdate(SqlUpdate updSql, Transaction t) {
return executeOrQueue(new PersistRequestUpdateSql(server, updSql, (SpiTransaction) t, persistExecute));
return executeOrQueue(new PersistRequestUpdateSql(server, (SpiSqlUpdate) updSql, (SpiTransaction) t, persistExecute));
}
/**
@@ -237,6 +237,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
return 0;
}
@Override
public void merge(Object bean) {
}
@Override
public void merge(Object bean, MergeOptions options) {
@@ -800,6 +805,16 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
return 0;
}
@Override
public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
}
@Override
public int[] executeBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction) {
return new int[0];
}
@Override
public int execute(CallableSql callableSql, Transaction t) {
return 0;