Polishing.
Delegate BatchJdbcOperations calls to NamedParameterJdbcOperations. Refine since and deprecation tags. See #1616
This commit is contained in:
@@ -15,49 +15,35 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.PreparedStatementCallback;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreator;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
|
||||
import org.springframework.jdbc.core.RowMapperResultSetExtractor;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
|
||||
import org.springframework.jdbc.core.namedparam.ParsedSql;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Counterpart to {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} containing methods for
|
||||
* performing batch updates with generated keys.
|
||||
*
|
||||
* @author Chirag Tailor
|
||||
* @author Mark Paluch
|
||||
* @since 2.4
|
||||
* @deprecated Use the standard {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} instead.
|
||||
* @deprecated since 3.2. Use {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations#batchUpdate}
|
||||
* methods instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
public class BatchJdbcOperations {
|
||||
|
||||
private final JdbcOperations jdbcOperations;
|
||||
private final NamedParameterJdbcOperations jdbcOperations;
|
||||
|
||||
public BatchJdbcOperations(JdbcOperations jdbcOperations) {
|
||||
this.jdbcOperations = jdbcOperations;
|
||||
this.jdbcOperations = new NamedParameterJdbcTemplate(jdbcOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
|
||||
*
|
||||
*
|
||||
* @param sql the SQL statement to execute
|
||||
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
|
||||
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
|
||||
@@ -69,12 +55,12 @@ public class BatchJdbcOperations {
|
||||
* @since 2.4
|
||||
*/
|
||||
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generatedKeyHolder) {
|
||||
return batchUpdate(sql, batchArgs, generatedKeyHolder, null);
|
||||
return jdbcOperations.batchUpdate(sql, batchArgs, generatedKeyHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
|
||||
*
|
||||
*
|
||||
* @param sql the SQL statement to execute
|
||||
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
|
||||
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
|
||||
@@ -88,87 +74,6 @@ public class BatchJdbcOperations {
|
||||
*/
|
||||
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generatedKeyHolder,
|
||||
@Nullable String[] keyColumnNames) {
|
||||
|
||||
if (batchArgs.length == 0) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||
SqlParameterSource paramSource = batchArgs[0];
|
||||
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
|
||||
List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
|
||||
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
|
||||
if (keyColumnNames != null) {
|
||||
pscf.setGeneratedKeysColumnNames(keyColumnNames);
|
||||
} else {
|
||||
pscf.setReturnGeneratedKeys(true);
|
||||
}
|
||||
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
|
||||
PreparedStatementCreator psc = pscf.newPreparedStatementCreator(params);
|
||||
BatchPreparedStatementSetter bpss = new BatchPreparedStatementSetter() {
|
||||
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
Object[] values = NamedParameterUtils.buildValueArray(parsedSql, batchArgs[i], null);
|
||||
pscf.newPreparedStatementSetter(values).setValues(ps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return batchArgs.length;
|
||||
}
|
||||
};
|
||||
PreparedStatementCallback<int[]> preparedStatementCallback = ps -> {
|
||||
|
||||
int batchSize = bpss.getBatchSize();
|
||||
generatedKeyHolder.getKeyList().clear();
|
||||
if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
|
||||
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
|
||||
bpss.setValues(ps, i);
|
||||
ps.addBatch();
|
||||
}
|
||||
int[] results = ps.executeBatch();
|
||||
storeGeneratedKeys(generatedKeyHolder, ps, batchSize);
|
||||
return results;
|
||||
} else {
|
||||
|
||||
List<Integer> rowsAffected = new ArrayList<>();
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
|
||||
bpss.setValues(ps, i);
|
||||
rowsAffected.add(ps.executeUpdate());
|
||||
storeGeneratedKeys(generatedKeyHolder, ps, 1);
|
||||
}
|
||||
int[] rowsAffectedArray = new int[rowsAffected.size()];
|
||||
for (int i = 0; i < rowsAffectedArray.length; i++) {
|
||||
rowsAffectedArray[i] = rowsAffected.get(i);
|
||||
}
|
||||
return rowsAffectedArray;
|
||||
}
|
||||
};
|
||||
int[] result = jdbcOperations.execute(psc, preparedStatementCallback);
|
||||
Assert.state(result != null, "No result array");
|
||||
return result;
|
||||
}
|
||||
|
||||
private void storeGeneratedKeys(KeyHolder generatedKeyHolder, PreparedStatement ps, int rowsExpected)
|
||||
throws SQLException {
|
||||
|
||||
List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
|
||||
ResultSet keys = ps.getGeneratedKeys();
|
||||
if (keys != null) {
|
||||
|
||||
try {
|
||||
|
||||
RowMapperResultSetExtractor<Map<String, Object>> rse = new RowMapperResultSetExtractor<>(
|
||||
new ColumnMapRowMapper(), rowsExpected);
|
||||
// noinspection ConstantConditions
|
||||
generatedKeys.addAll(rse.extractData(keys));
|
||||
} finally {
|
||||
JdbcUtils.closeResultSet(keys);
|
||||
}
|
||||
}
|
||||
return jdbcOperations.batchUpdate(sql, batchArgs, generatedKeyHolder, keyColumnNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ public class InsertStrategyFactory {
|
||||
|
||||
/**
|
||||
* Constructor with additional {@link BatchJdbcOperations} constructor.
|
||||
*
|
||||
* @deprecated Use the {@link InsertStrategyFactory#InsertStrategyFactory(NamedParameterJdbcOperations, Dialect)}
|
||||
* instead.
|
||||
*
|
||||
* @deprecated since 3.2, use
|
||||
* {@link InsertStrategyFactory#InsertStrategyFactory(NamedParameterJdbcOperations, Dialect)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
public InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations,
|
||||
|
||||
@@ -65,6 +65,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for application events via {@link SimpleJdbcRepository}.
|
||||
@@ -81,7 +82,7 @@ class SimpleJdbcRepositoryEventsUnitTests {
|
||||
|
||||
private static final long generatedId = 4711L;
|
||||
|
||||
private CollectingEventPublisher publisher = new CollectingEventPublisher();
|
||||
private final CollectingEventPublisher publisher = new CollectingEventPublisher();
|
||||
|
||||
private DummyEntityRepository repository;
|
||||
private DefaultDataAccessStrategy dataAccessStrategy;
|
||||
@@ -306,7 +307,7 @@ class SimpleJdbcRepositoryEventsUnitTests {
|
||||
extends CrudRepository<DummyEntity, Long>, PagingAndSortingRepository<DummyEntity, Long> {}
|
||||
|
||||
static final class DummyEntity {
|
||||
@Id private final Long id;
|
||||
private final @Id Long id;
|
||||
|
||||
public DummyEntity(Long id) {
|
||||
this.id = id;
|
||||
@@ -316,34 +317,31 @@ class SimpleJdbcRepositoryEventsUnitTests {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public boolean equals(final Object o) {
|
||||
if (o == this)
|
||||
return true;
|
||||
if (!(o instanceof DummyEntity))
|
||||
return false;
|
||||
final DummyEntity other = (DummyEntity) o;
|
||||
final Object this$id = this.getId();
|
||||
final Object other$id = other.getId();
|
||||
if (this$id == null ? other$id != null : !this$id.equals(other$id))
|
||||
return false;
|
||||
return true;
|
||||
public DummyEntity withId(Long id) {
|
||||
return this.id == id ? this : new DummyEntity(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
DummyEntity that = (DummyEntity) o;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
final Object $id = this.getId();
|
||||
result = result * PRIME + ($id == null ? 43 : $id.hashCode());
|
||||
return result;
|
||||
return ObjectUtils.nullSafeHashCode(id);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SimpleJdbcRepositoryEventsUnitTests.DummyEntity(id=" + this.getId() + ")";
|
||||
}
|
||||
|
||||
public DummyEntity withId(Long id) {
|
||||
return this.id == id ? this : new DummyEntity(id);
|
||||
}
|
||||
}
|
||||
|
||||
static class CollectingEventPublisher implements ApplicationEventPublisher {
|
||||
|
||||
@@ -30,13 +30,17 @@ This should be significant more efficient, especially for complex aggregates, co
|
||||
+
|
||||
Currently, Single Query Loading is restricted in different ways:
|
||||
|
||||
1. The aggregate must not have nested collections, this includes `Map`.The plan is to remove this constraint in the future.
|
||||
1. The aggregate must not have nested collections, this includes `Map`.
|
||||
The plan is to remove this constraint in the future.
|
||||
|
||||
2. The aggregate must not use `AggregateReference` or embedded entities.The plan is to remove this constraint in the future.
|
||||
2. The aggregate must not use `AggregateReference` or embedded entities.
|
||||
The plan is to remove this constraint in the future.
|
||||
|
||||
3. The database dialect must support it.Of the dialects provided by Spring Data JDBC all but H2 and HSQL support this.H2 and HSQL don't support analytic functions (aka windowing functions).
|
||||
3. The database dialect must support it.Of the dialects provided by Spring Data JDBC all but H2 and HSQL support this.
|
||||
H2 and HSQL don't support analytic functions (aka windowing functions).
|
||||
|
||||
4. It only works for the find methods in `CrudRepository`, not for derived queries and not for annotated queries.The plan is to remove this constraint in the future.
|
||||
4. It only works for the find methods in `CrudRepository`, not for derived queries and not for annotated queries.
|
||||
The plan is to remove this constraint in the future.
|
||||
|
||||
5. Single Query Loading needs to be enabled in the `JdbcMappingContext`, by calling `setSingleQueryLoadingEnabled(true)`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user