add batch methods to SqlUpdate
This commit is contained in:
parent
a9fb8eaa2f
commit
1c1a1ed55a
4 changed files with 114 additions and 11 deletions
|
@ -1,6 +1,6 @@
|
|||
group = org.xbib
|
||||
name = database
|
||||
version = 0.0.3
|
||||
version = 0.0.4
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ public class SqlInsertImpl implements SqlInsert {
|
|||
|
||||
@Override
|
||||
public void insertBatch() {
|
||||
int[] result = updateBatch();
|
||||
int[] result = insertBatchInternal();
|
||||
for (int r : result) {
|
||||
// Tolerate SUCCESS_NO_INFO for older versions of Oracle
|
||||
if (r != 1 && r != Statement.SUCCESS_NO_INFO) {
|
||||
|
@ -280,7 +280,7 @@ public class SqlInsertImpl implements SqlInsert {
|
|||
|
||||
@Override
|
||||
public int[] insertBatchUnchecked() {
|
||||
return updateBatch();
|
||||
return insertBatchInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -414,7 +414,7 @@ public class SqlInsertImpl implements SqlInsert {
|
|||
return pkArgName != null || pkSeqName != null || pkLong != null;
|
||||
}
|
||||
|
||||
private int[] updateBatch() {
|
||||
private int[] insertBatchInternal() {
|
||||
batch();
|
||||
|
||||
if (batched == null || batched.size() == 0) {
|
||||
|
@ -682,7 +682,7 @@ public class SqlInsertImpl implements SqlInsert {
|
|||
return b == null ? null : b ? "Y" : "N";
|
||||
}
|
||||
|
||||
private class Batch {
|
||||
private static class Batch {
|
||||
private final List<Object> parameterList; // !null ==> traditional ? args
|
||||
private final Map<String, Object> parameterMap; // !null ==> named :abc args
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@ public interface SqlUpdate {
|
|||
|
||||
SqlUpdate apply(Apply apply);
|
||||
|
||||
SqlUpdate batch();
|
||||
|
||||
/**
|
||||
* Execute the SQL update and return the number of rows was affected.
|
||||
*/
|
||||
|
@ -90,6 +92,10 @@ public interface SqlUpdate {
|
|||
*/
|
||||
void update(int expectedRowsUpdated);
|
||||
|
||||
void updateBatch();
|
||||
|
||||
int[] updateBatchUnchecked();
|
||||
|
||||
interface Apply {
|
||||
void apply(SqlUpdate update);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.xbib.jdbc.query;
|
||||
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import org.xbib.jdbc.query.util.DebugSql;
|
||||
import org.xbib.jdbc.query.util.InternalStringReader;
|
||||
|
@ -14,6 +15,7 @@ import java.sql.PreparedStatement;
|
|||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -35,6 +37,8 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
|
||||
private final Options options;
|
||||
|
||||
private List<Batch> batched;
|
||||
|
||||
private List<Object> parameterList;
|
||||
|
||||
private Map<String, Object> parameterMap;
|
||||
|
@ -247,6 +251,20 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlUpdate batch() {
|
||||
if ((parameterList != null && !parameterList.isEmpty())
|
||||
|| (parameterMap != null && !parameterMap.isEmpty())) {
|
||||
if (batched == null) {
|
||||
batched = new ArrayList<>();
|
||||
}
|
||||
batched.add(new Batch(parameterList, parameterMap));
|
||||
parameterList = new ArrayList<>();
|
||||
parameterMap = new HashMap<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update() {
|
||||
return updateInternal(0);
|
||||
|
@ -257,13 +275,85 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
updateInternal(expectedNumAffectedRows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBatch() {
|
||||
int[] result = updateBatchInternal();
|
||||
for (int r : result) {
|
||||
// Tolerate SUCCESS_NO_INFO for older versions of Oracle
|
||||
if (r != 1 && r != Statement.SUCCESS_NO_INFO) {
|
||||
throw new DatabaseException("Batch did not return the expected result: " + Arrays.toString(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] updateBatchUnchecked() {
|
||||
return updateBatchInternal();
|
||||
}
|
||||
|
||||
private int[] updateBatchInternal() {
|
||||
batch();
|
||||
if (batched == null || batched.size() == 0) {
|
||||
throw new DatabaseException("Batch insert requires parameters");
|
||||
}
|
||||
PreparedStatement ps = null;
|
||||
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
||||
String executeSql = sql;
|
||||
Object[] firstRowParameters = null;
|
||||
List<Object[]> parameters = new ArrayList<>();
|
||||
boolean isSuccess = false;
|
||||
String errorCode = null;
|
||||
Exception logEx = null;
|
||||
try {
|
||||
for (Batch batch : batched) {
|
||||
MixedParameterSql mpSql = new MixedParameterSql(sql, batch.parameterList, batch.parameterMap);
|
||||
if (firstRowParameters == null) {
|
||||
executeSql = mpSql.getSqlToExecute();
|
||||
firstRowParameters = mpSql.getArgs();
|
||||
} else {
|
||||
if (!executeSql.equals(mpSql.getSqlToExecute())) {
|
||||
throw new DatabaseException("All rows in a batch must use parameters in the same way. \nSQL1: "
|
||||
+ executeSql + "\nSQL2: " + mpSql.getSqlToExecute());
|
||||
}
|
||||
}
|
||||
parameters.add(mpSql.getArgs());
|
||||
}
|
||||
if (connection != null) {
|
||||
ps = connection.prepareStatement(executeSql);
|
||||
for (Object[] params : parameters) {
|
||||
adaptor.addParameters(ps, params);
|
||||
ps.addBatch();
|
||||
}
|
||||
metric.checkpoint("prep");
|
||||
int[] numAffectedRows = ps.executeBatch();
|
||||
metric.checkpoint("execBatch", parameters.size());
|
||||
isSuccess = true;
|
||||
return numAffectedRows;
|
||||
} else {
|
||||
return new int[]{-1};
|
||||
}
|
||||
} catch (WrongNumberOfRowsException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
errorCode = options.generateErrorCode();
|
||||
logEx = e;
|
||||
throw DatabaseException.wrap(DebugSql.exceptionMessage(executeSql, firstRowParameters, errorCode, options), e);
|
||||
} finally {
|
||||
adaptor.closeQuietly(ps, log);
|
||||
metric.done("close");
|
||||
if (isSuccess) {
|
||||
DebugSql.logSuccess("Insert", log, metric, executeSql, firstRowParameters, options);
|
||||
} else {
|
||||
DebugSql.logError("Insert", log, metric, errorCode, executeSql, firstRowParameters, options, logEx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int updateInternal(int expectedNumAffectedRows) {
|
||||
PreparedStatement ps = null;
|
||||
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
||||
|
||||
String executeSql = sql;
|
||||
Object[] parameters = null;
|
||||
|
||||
boolean isSuccess = false;
|
||||
String errorCode = null;
|
||||
Exception logEx = null;
|
||||
|
@ -271,7 +361,6 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
MixedParameterSql mpSql = new MixedParameterSql(sql, parameterList, parameterMap);
|
||||
executeSql = mpSql.getSqlToExecute();
|
||||
parameters = mpSql.getArgs();
|
||||
|
||||
if (connection != null) {
|
||||
ps = connection.prepareStatement(executeSql);
|
||||
adaptor.addParameters(ps, parameters);
|
||||
|
@ -306,7 +395,6 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private SqlUpdate positionalArg(Object arg) {
|
||||
if (parameterList == null) {
|
||||
parameterList = new ArrayList<>();
|
||||
|
@ -315,7 +403,6 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
private SqlUpdate namedArg(String argName, Object arg) {
|
||||
if (parameterMap == null) {
|
||||
parameterMap = new HashMap<>();
|
||||
|
@ -330,4 +417,14 @@ public class SqlUpdateImpl implements SqlUpdate {
|
|||
private String booleanToString(Boolean b) {
|
||||
return b == null ? null : b ? "Y" : "N";
|
||||
}
|
||||
|
||||
private static class Batch {
|
||||
private final List<Object> parameterList; // !null ==> traditional ? args
|
||||
private final Map<String, Object> parameterMap; // !null ==> named :abc args
|
||||
|
||||
public Batch(List<Object> parameterList, Map<String, Object> parameterMap) {
|
||||
this.parameterList = parameterList;
|
||||
this.parameterMap = parameterMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue