[jOOQ/jOOQ#9806] Add Batch.executeAsync() methods

This commit is contained in:
Lukas Eder 2020-02-07 10:49:15 +01:00
parent 92de670f5d
commit fb2c0cc910
5 changed files with 126 additions and 37 deletions

View File

@ -39,6 +39,8 @@ package org.jooq;
import java.io.Serializable;
import java.sql.Statement;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import org.jooq.exception.DataAccessException;
@ -73,6 +75,27 @@ public interface Batch extends Serializable {
*/
int[] execute() throws DataAccessException;
/**
* Execute the batch operation in a new {@link CompletionStage}.
* <p>
* The result is asynchronously completed by a task running in an
* {@link Executor} provided by the underlying
* {@link Configuration#executorProvider()}.
*
* @see Statement#executeBatch()
*/
CompletionStage<int[]> executeAsync();
/**
* Execute the query in a new {@link CompletionStage} that is asynchronously
* completed by a task running in the given executor.
*/
CompletionStage<int[]> executeAsync(Executor executor);
/**
* Get the number of executed queries in this batch operation
*/

View File

@ -0,0 +1,81 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.Tools.blocking;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import org.jooq.Batch;
import org.jooq.Configuration;
import org.jooq.DSLContext;
/**
* @author Lukas Eder
*/
abstract class AbstractBatch implements Batch {
/**
* Generated UID
*/
private static final long serialVersionUID = 5898924458502836002L;
final Configuration configuration;
final DSLContext dsl;
AbstractBatch(Configuration configuration) {
this.configuration = configuration;
this.dsl = DSL.using(configuration);
}
@Override
public final CompletionStage<int[]> executeAsync() {
return executeAsync(configuration.executorProvider().provide());
}
@Override
public final CompletionStage<int[]> executeAsync(Executor executor) {
return ExecutorProviderCompletionStage.of(CompletableFuture.supplyAsync(blocking(this::execute), executor), () -> executor);
}
}

View File

@ -46,10 +46,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jooq.Batch;
import org.jooq.BatchBindStep;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.Query;
import org.jooq.TableRecord;
@ -60,21 +58,19 @@ import org.jooq.exception.DataAccessException;
/**
* @author Lukas Eder
*/
final class BatchCRUD implements Batch {
final class BatchCRUD extends AbstractBatch {
/**
* Generated UID
*/
private static final long serialVersionUID = -2935544935267715011L;
private final DSLContext create;
private final Configuration configuration;
private final TableRecord<?>[] records;
private final Action action;
BatchCRUD(Configuration configuration, Action action, TableRecord<?>[] records) {
this.create = DSL.using(configuration);
this.configuration = configuration;
super(configuration);
this.action = action;
this.records = records;
}
@ -89,12 +85,10 @@ final class BatchCRUD implements Batch {
// [#1180] Run batch queries with BatchMultiple, if no bind variables
// should be used...
if (executeStaticStatements(configuration.settings())) {
if (executeStaticStatements(configuration.settings()))
return executeStatic();
}
else {
else
return executePrepared();
}
}
private final int[] executePrepared() {
@ -146,22 +140,19 @@ final class BatchCRUD implements Batch {
// The order is preserved as much as possible
List<Integer> result = new ArrayList<>();
for (Entry<String, List<Query>> entry : queries.entrySet()) {
BatchBindStep batch = create.batch(entry.getValue().get(0));
BatchBindStep batch = dsl.batch(entry.getValue().get(0));
for (Query query : entry.getValue()) {
for (Query query : entry.getValue())
batch.bind(query.getBindValues().toArray());
}
int[] array = batch.execute();
for (int i : array) {
for (int i : array)
result.add(i);
}
}
int[] array = new int[result.size()];
for (int i = 0; i < result.size(); i++) {
for (int i = 0; i < result.size(); i++)
array[i] = result.get(i);
}
updateChangedFlag();
return array;
@ -186,9 +177,8 @@ final class BatchCRUD implements Batch {
catch (QueryCollectorSignal e) {
Query query = e.getQuery();
if (query.isExecutable()) {
if (query.isExecutable())
queries.add(query);
}
}
finally {
records[i].attach(previous);
@ -196,7 +186,7 @@ final class BatchCRUD implements Batch {
}
// Resulting statements can be batch executed in their requested order
int[] result = create.batch(queries).execute();
int[] result = dsl.batch(queries).execute();
updateChangedFlag();
return result;
}
@ -227,9 +217,8 @@ final class BatchCRUD implements Batch {
// [#3362] If new records (fetched = false) are batch-stored twice in a row, the second
// batch-store needs to generate an UPDATE statement.
if (record instanceof AbstractRecord) {
if (record instanceof AbstractRecord)
((AbstractRecord) record).fetched = action != Action.DELETE;
}
}
}

View File

@ -40,7 +40,6 @@ package org.jooq.impl;
import java.sql.Connection;
import java.sql.SQLException;
import org.jooq.Batch;
import org.jooq.Configuration;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
@ -51,18 +50,18 @@ import org.jooq.exception.ControlFlowSignal;
/**
* @author Lukas Eder
*/
final class BatchMultiple implements Batch {
final class BatchMultiple extends AbstractBatch {
/**
* Generated UID
*/
private static final long serialVersionUID = -7337667281292354043L;
private final Configuration configuration;
private final Query[] queries;
public BatchMultiple(Configuration configuration, Query... queries) {
this.configuration = configuration;
super(configuration);
this.queries = queries;
}

View File

@ -54,7 +54,6 @@ import java.util.Map.Entry;
import org.jooq.BatchBindStep;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
@ -67,7 +66,7 @@ import org.jooq.tools.JooqLogger;
/**
* @author Lukas Eder
*/
final class BatchSingle implements BatchBindStep {
final class BatchSingle extends AbstractBatch implements BatchBindStep {
/**
* Generated UID
@ -75,21 +74,19 @@ final class BatchSingle implements BatchBindStep {
private static final long serialVersionUID = 3793967258181493207L;
private static final JooqLogger log = JooqLogger.getLogger(BatchSingle.class);
private final DSLContext create;
private final Configuration configuration;
private final Query query;
private final Map<String, List<Integer>> nameToIndexMapping;
private final List<Object[]> allBindValues;
private final int expectedBindValues;
public BatchSingle(Configuration configuration, Query query) {
super(configuration);
int i = 0;
ParamCollector collector = new ParamCollector(configuration, false);
collector.visit(query);
this.create = DSL.using(configuration);
this.configuration = configuration;
this.query = query;
this.allBindValues = new ArrayList<>();
this.nameToIndexMapping = new LinkedHashMap<>();
@ -132,7 +129,7 @@ final class BatchSingle implements BatchBindStep {
@SafeVarargs
public final BatchSingle bind(Map<String, Object>... namedBindValues) {
List<Object> defaultValues = create.extractBindValues(query);
List<Object> defaultValues = dsl.extractBindValues(query);
Object[][] bindValues = new Object[namedBindValues.length][];
for (int row = 0; row < bindValues.length; row++) {
@ -210,7 +207,7 @@ final class BatchSingle implements BatchBindStep {
listener.renderStart(ctx);
// [#1520] TODO: Should the number of bind values be checked, here?
ctx.sql(create.render(query));
ctx.sql(dsl.render(query));
listener.renderEnd(ctx);
listener.prepareStart(ctx);
@ -275,9 +272,9 @@ final class BatchSingle implements BatchBindStep {
for (int i = 0; i < bindValues.length; i++)
query.bind(i + 1, bindValues[i]);
queries.add(create.query(query.getSQL(INLINED)));
queries.add(dsl.query(query.getSQL(INLINED)));
}
return create.batch(queries).execute();
return dsl.batch(queries).execute();
}
}