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
|
group = org.xbib
|
||||||
name = database
|
name = database
|
||||||
version = 0.0.3
|
version = 0.0.4
|
||||||
|
|
||||||
org.gradle.warning.mode = ALL
|
org.gradle.warning.mode = ALL
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,7 @@ public class SqlInsertImpl implements SqlInsert {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insertBatch() {
|
public void insertBatch() {
|
||||||
int[] result = updateBatch();
|
int[] result = insertBatchInternal();
|
||||||
for (int r : result) {
|
for (int r : result) {
|
||||||
// Tolerate SUCCESS_NO_INFO for older versions of Oracle
|
// Tolerate SUCCESS_NO_INFO for older versions of Oracle
|
||||||
if (r != 1 && r != Statement.SUCCESS_NO_INFO) {
|
if (r != 1 && r != Statement.SUCCESS_NO_INFO) {
|
||||||
|
@ -280,7 +280,7 @@ public class SqlInsertImpl implements SqlInsert {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] insertBatchUnchecked() {
|
public int[] insertBatchUnchecked() {
|
||||||
return updateBatch();
|
return insertBatchInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -414,7 +414,7 @@ public class SqlInsertImpl implements SqlInsert {
|
||||||
return pkArgName != null || pkSeqName != null || pkLong != null;
|
return pkArgName != null || pkSeqName != null || pkLong != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] updateBatch() {
|
private int[] insertBatchInternal() {
|
||||||
batch();
|
batch();
|
||||||
|
|
||||||
if (batched == null || batched.size() == 0) {
|
if (batched == null || batched.size() == 0) {
|
||||||
|
@ -682,7 +682,7 @@ public class SqlInsertImpl implements SqlInsert {
|
||||||
return b == null ? null : b ? "Y" : "N";
|
return b == null ? null : b ? "Y" : "N";
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Batch {
|
private static class Batch {
|
||||||
private final List<Object> parameterList; // !null ==> traditional ? args
|
private final List<Object> parameterList; // !null ==> traditional ? args
|
||||||
private final Map<String, Object> parameterMap; // !null ==> named :abc args
|
private final Map<String, Object> parameterMap; // !null ==> named :abc args
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,8 @@ public interface SqlUpdate {
|
||||||
|
|
||||||
SqlUpdate apply(Apply apply);
|
SqlUpdate apply(Apply apply);
|
||||||
|
|
||||||
|
SqlUpdate batch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the SQL update and return the number of rows was affected.
|
* Execute the SQL update and return the number of rows was affected.
|
||||||
*/
|
*/
|
||||||
|
@ -90,6 +92,10 @@ public interface SqlUpdate {
|
||||||
*/
|
*/
|
||||||
void update(int expectedRowsUpdated);
|
void update(int expectedRowsUpdated);
|
||||||
|
|
||||||
|
void updateBatch();
|
||||||
|
|
||||||
|
int[] updateBatchUnchecked();
|
||||||
|
|
||||||
interface Apply {
|
interface Apply {
|
||||||
void apply(SqlUpdate update);
|
void apply(SqlUpdate update);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.xbib.jdbc.query;
|
package org.xbib.jdbc.query;
|
||||||
|
|
||||||
|
import java.sql.Statement;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import org.xbib.jdbc.query.util.DebugSql;
|
import org.xbib.jdbc.query.util.DebugSql;
|
||||||
import org.xbib.jdbc.query.util.InternalStringReader;
|
import org.xbib.jdbc.query.util.InternalStringReader;
|
||||||
|
@ -14,6 +15,7 @@ import java.sql.PreparedStatement;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -35,6 +37,8 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
|
|
||||||
private final Options options;
|
private final Options options;
|
||||||
|
|
||||||
|
private List<Batch> batched;
|
||||||
|
|
||||||
private List<Object> parameterList;
|
private List<Object> parameterList;
|
||||||
|
|
||||||
private Map<String, Object> parameterMap;
|
private Map<String, Object> parameterMap;
|
||||||
|
@ -247,6 +251,20 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
return this;
|
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
|
@Override
|
||||||
public int update() {
|
public int update() {
|
||||||
return updateInternal(0);
|
return updateInternal(0);
|
||||||
|
@ -257,13 +275,85 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
updateInternal(expectedNumAffectedRows);
|
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) {
|
private int updateInternal(int expectedNumAffectedRows) {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
||||||
|
|
||||||
String executeSql = sql;
|
String executeSql = sql;
|
||||||
Object[] parameters = null;
|
Object[] parameters = null;
|
||||||
|
|
||||||
boolean isSuccess = false;
|
boolean isSuccess = false;
|
||||||
String errorCode = null;
|
String errorCode = null;
|
||||||
Exception logEx = null;
|
Exception logEx = null;
|
||||||
|
@ -271,7 +361,6 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
MixedParameterSql mpSql = new MixedParameterSql(sql, parameterList, parameterMap);
|
MixedParameterSql mpSql = new MixedParameterSql(sql, parameterList, parameterMap);
|
||||||
executeSql = mpSql.getSqlToExecute();
|
executeSql = mpSql.getSqlToExecute();
|
||||||
parameters = mpSql.getArgs();
|
parameters = mpSql.getArgs();
|
||||||
|
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
ps = connection.prepareStatement(executeSql);
|
ps = connection.prepareStatement(executeSql);
|
||||||
adaptor.addParameters(ps, parameters);
|
adaptor.addParameters(ps, parameters);
|
||||||
|
@ -306,7 +395,6 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private SqlUpdate positionalArg(Object arg) {
|
private SqlUpdate positionalArg(Object arg) {
|
||||||
if (parameterList == null) {
|
if (parameterList == null) {
|
||||||
parameterList = new ArrayList<>();
|
parameterList = new ArrayList<>();
|
||||||
|
@ -315,7 +403,6 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private SqlUpdate namedArg(String argName, Object arg) {
|
private SqlUpdate namedArg(String argName, Object arg) {
|
||||||
if (parameterMap == null) {
|
if (parameterMap == null) {
|
||||||
parameterMap = new HashMap<>();
|
parameterMap = new HashMap<>();
|
||||||
|
@ -330,4 +417,14 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
private String booleanToString(Boolean b) {
|
private String booleanToString(Boolean b) {
|
||||||
return b == null ? null : b ? "Y" : "N";
|
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