Skip to content

Commit a72bf1a

Browse files
committed
Polishing.
Delegate BatchJdbcOperations calls to NamedParameterJdbcOperations. Refine since and deprecation tags. See #1616
1 parent 5d6d575 commit a72bf1a

File tree

4 files changed

+39
-132
lines changed

4 files changed

+39
-132
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BatchJdbcOperations.java

Lines changed: 11 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,35 @@
1515
*/
1616
package org.springframework.data.jdbc.core.convert;
1717

18-
import java.sql.PreparedStatement;
19-
import java.sql.ResultSet;
20-
import java.sql.SQLException;
21-
import java.util.ArrayList;
22-
import java.util.List;
23-
import java.util.Map;
24-
25-
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
26-
import org.springframework.jdbc.core.ColumnMapRowMapper;
2718
import org.springframework.jdbc.core.JdbcOperations;
28-
import org.springframework.jdbc.core.PreparedStatementCallback;
29-
import org.springframework.jdbc.core.PreparedStatementCreator;
30-
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
31-
import org.springframework.jdbc.core.RowMapperResultSetExtractor;
32-
import org.springframework.jdbc.core.SqlParameter;
33-
import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
34-
import org.springframework.jdbc.core.namedparam.ParsedSql;
19+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
20+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
3521
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
36-
import org.springframework.jdbc.support.JdbcUtils;
3722
import org.springframework.jdbc.support.KeyHolder;
3823
import org.springframework.lang.Nullable;
39-
import org.springframework.util.Assert;
4024

4125
/**
4226
* Counterpart to {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} containing methods for
4327
* performing batch updates with generated keys.
4428
*
4529
* @author Chirag Tailor
30+
* @author Mark Paluch
4631
* @since 2.4
47-
* @deprecated Use the standard {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} instead.
32+
* @deprecated since 3.2. Use {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations#batchUpdate}
33+
* methods instead.
4834
*/
4935
@Deprecated(since = "3.2")
5036
public class BatchJdbcOperations {
5137

52-
private final JdbcOperations jdbcOperations;
38+
private final NamedParameterJdbcOperations jdbcOperations;
5339

5440
public BatchJdbcOperations(JdbcOperations jdbcOperations) {
55-
this.jdbcOperations = jdbcOperations;
41+
this.jdbcOperations = new NamedParameterJdbcTemplate(jdbcOperations);
5642
}
5743

5844
/**
5945
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
60-
*
46+
*
6147
* @param sql the SQL statement to execute
6248
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
6349
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
@@ -69,12 +55,12 @@ public BatchJdbcOperations(JdbcOperations jdbcOperations) {
6955
* @since 2.4
7056
*/
7157
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generatedKeyHolder) {
72-
return batchUpdate(sql, batchArgs, generatedKeyHolder, null);
58+
return jdbcOperations.batchUpdate(sql, batchArgs, generatedKeyHolder);
7359
}
7460

7561
/**
7662
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
77-
*
63+
*
7864
* @param sql the SQL statement to execute
7965
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
8066
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
@@ -88,87 +74,6 @@ int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generate
8874
*/
8975
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generatedKeyHolder,
9076
@Nullable String[] keyColumnNames) {
91-
92-
if (batchArgs.length == 0) {
93-
return new int[0];
94-
}
95-
96-
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
97-
SqlParameterSource paramSource = batchArgs[0];
98-
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
99-
List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
100-
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
101-
if (keyColumnNames != null) {
102-
pscf.setGeneratedKeysColumnNames(keyColumnNames);
103-
} else {
104-
pscf.setReturnGeneratedKeys(true);
105-
}
106-
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
107-
PreparedStatementCreator psc = pscf.newPreparedStatementCreator(params);
108-
BatchPreparedStatementSetter bpss = new BatchPreparedStatementSetter() {
109-
110-
@Override
111-
public void setValues(PreparedStatement ps, int i) throws SQLException {
112-
Object[] values = NamedParameterUtils.buildValueArray(parsedSql, batchArgs[i], null);
113-
pscf.newPreparedStatementSetter(values).setValues(ps);
114-
}
115-
116-
@Override
117-
public int getBatchSize() {
118-
return batchArgs.length;
119-
}
120-
};
121-
PreparedStatementCallback<int[]> preparedStatementCallback = ps -> {
122-
123-
int batchSize = bpss.getBatchSize();
124-
generatedKeyHolder.getKeyList().clear();
125-
if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
126-
127-
for (int i = 0; i < batchSize; i++) {
128-
129-
bpss.setValues(ps, i);
130-
ps.addBatch();
131-
}
132-
int[] results = ps.executeBatch();
133-
storeGeneratedKeys(generatedKeyHolder, ps, batchSize);
134-
return results;
135-
} else {
136-
137-
List<Integer> rowsAffected = new ArrayList<>();
138-
for (int i = 0; i < batchSize; i++) {
139-
140-
bpss.setValues(ps, i);
141-
rowsAffected.add(ps.executeUpdate());
142-
storeGeneratedKeys(generatedKeyHolder, ps, 1);
143-
}
144-
int[] rowsAffectedArray = new int[rowsAffected.size()];
145-
for (int i = 0; i < rowsAffectedArray.length; i++) {
146-
rowsAffectedArray[i] = rowsAffected.get(i);
147-
}
148-
return rowsAffectedArray;
149-
}
150-
};
151-
int[] result = jdbcOperations.execute(psc, preparedStatementCallback);
152-
Assert.state(result != null, "No result array");
153-
return result;
154-
}
155-
156-
private void storeGeneratedKeys(KeyHolder generatedKeyHolder, PreparedStatement ps, int rowsExpected)
157-
throws SQLException {
158-
159-
List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
160-
ResultSet keys = ps.getGeneratedKeys();
161-
if (keys != null) {
162-
163-
try {
164-
165-
RowMapperResultSetExtractor<Map<String, Object>> rse = new RowMapperResultSetExtractor<>(
166-
new ColumnMapRowMapper(), rowsExpected);
167-
// noinspection ConstantConditions
168-
generatedKeys.addAll(rse.extractData(keys));
169-
} finally {
170-
JdbcUtils.closeResultSet(keys);
171-
}
172-
}
77+
return jdbcOperations.batchUpdate(sql, batchArgs, generatedKeyHolder, keyColumnNames);
17378
}
17479
}

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/InsertStrategyFactory.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ public InsertStrategyFactory(NamedParameterJdbcOperations jdbcOperations, Dialec
4343

4444
/**
4545
* Constructor with additional {@link BatchJdbcOperations} constructor.
46-
*
47-
* @deprecated Use the {@link InsertStrategyFactory#InsertStrategyFactory(NamedParameterJdbcOperations, Dialect)}
48-
* instead.
46+
*
47+
* @deprecated since 3.2, use
48+
* {@link InsertStrategyFactory#InsertStrategyFactory(NamedParameterJdbcOperations, Dialect)} instead.
4949
*/
5050
@Deprecated(since = "3.2")
5151
public InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations,

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
6666
import org.springframework.jdbc.support.KeyHolder;
6767
import org.springframework.lang.Nullable;
68+
import org.springframework.util.ObjectUtils;
6869

6970
/**
7071
* Unit tests for application events via {@link SimpleJdbcRepository}.
@@ -81,7 +82,7 @@ class SimpleJdbcRepositoryEventsUnitTests {
8182

8283
private static final long generatedId = 4711L;
8384

84-
private CollectingEventPublisher publisher = new CollectingEventPublisher();
85+
private final CollectingEventPublisher publisher = new CollectingEventPublisher();
8586

8687
private DummyEntityRepository repository;
8788
private DefaultDataAccessStrategy dataAccessStrategy;
@@ -306,7 +307,7 @@ interface DummyEntityRepository
306307
extends CrudRepository<DummyEntity, Long>, PagingAndSortingRepository<DummyEntity, Long> {}
307308

308309
static final class DummyEntity {
309-
@Id private final Long id;
310+
private final @Id Long id;
310311

311312
public DummyEntity(Long id) {
312313
this.id = id;
@@ -316,34 +317,31 @@ public Long getId() {
316317
return this.id;
317318
}
318319

319-
public boolean equals(final Object o) {
320-
if (o == this)
320+
public DummyEntity withId(Long id) {
321+
return this.id == id ? this : new DummyEntity(id);
322+
}
323+
324+
@Override
325+
public boolean equals(Object o) {
326+
if (this == o)
321327
return true;
322-
if (!(o instanceof DummyEntity))
323-
return false;
324-
final DummyEntity other = (DummyEntity) o;
325-
final Object this$id = this.getId();
326-
final Object other$id = other.getId();
327-
if (this$id == null ? other$id != null : !this$id.equals(other$id))
328+
if (o == null || getClass() != o.getClass())
328329
return false;
329-
return true;
330+
331+
DummyEntity that = (DummyEntity) o;
332+
333+
return ObjectUtils.nullSafeEquals(id, that.id);
330334
}
331335

336+
@Override
332337
public int hashCode() {
333-
final int PRIME = 59;
334-
int result = 1;
335-
final Object $id = this.getId();
336-
result = result * PRIME + ($id == null ? 43 : $id.hashCode());
337-
return result;
338+
return ObjectUtils.nullSafeHashCode(id);
338339
}
339340

340341
public String toString() {
341342
return "SimpleJdbcRepositoryEventsUnitTests.DummyEntity(id=" + this.getId() + ")";
342343
}
343344

344-
public DummyEntity withId(Long id) {
345-
return this.id == id ? this : new DummyEntity(id);
346-
}
347345
}
348346

349347
static class CollectingEventPublisher implements ApplicationEventPublisher {

src/main/antora/modules/ROOT/pages/jdbc/entity-persistence.adoc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@ This should be significant more efficient, especially for complex aggregates, co
3030
+
3131
Currently, Single Query Loading is restricted in different ways:
3232

33-
1. The aggregate must not have nested collections, this includes `Map`.The plan is to remove this constraint in the future.
33+
1. The aggregate must not have nested collections, this includes `Map`.
34+
The plan is to remove this constraint in the future.
3435

35-
2. The aggregate must not use `AggregateReference` or embedded entities.The plan is to remove this constraint in the future.
36+
2. The aggregate must not use `AggregateReference` or embedded entities.
37+
The plan is to remove this constraint in the future.
3638

37-
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).
39+
3. The database dialect must support it.Of the dialects provided by Spring Data JDBC all but H2 and HSQL support this.
40+
H2 and HSQL don't support analytic functions (aka windowing functions).
3841

39-
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.
42+
4. It only works for the find methods in `CrudRepository`, not for derived queries and not for annotated queries.
43+
The plan is to remove this constraint in the future.
4044

4145
5. Single Query Loading needs to be enabled in the `JdbcMappingContext`, by calling `setSingleQueryLoadingEnabled(true)`
4246

0 commit comments

Comments
 (0)