Replace BatchJdbcOperations with Spring's NamedParameterJdbcOperations.

BatchJdbcOperations is still there, but deprecated, and not used except for deprecated places kept for backward compatibility.

This is possible since Spring Framework made the features offered by `BatchJdbcOperations` part of `NamedParameterJdbcOperations`.

Closes #1616
This commit is contained in:
Jens Schauder
2023-09-18 10:04:11 +02:00
committed by Mark Paluch
parent 6887ca78a5
commit 5d6d575ab2
11 changed files with 81 additions and 62 deletions

View File

@@ -44,7 +44,9 @@ import org.springframework.util.Assert;
*
* @author Chirag Tailor
* @since 2.4
* @deprecated Use the standard {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} instead.
*/
@Deprecated(since = "3.2")
public class BatchJdbcOperations {
private final JdbcOperations jdbcOperations;

View File

@@ -23,6 +23,7 @@ import java.util.Optional;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.IdGeneration;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.lang.Nullable;
@@ -33,21 +34,23 @@ import org.springframework.lang.Nullable;
*
* @author Chirag Tailor
* @author Kurt Niemi
* @author Jens Schauder
* @since 2.4
*/
class IdGeneratingBatchInsertStrategy implements BatchInsertStrategy {
private final InsertStrategy insertStrategy;
private final Dialect dialect;
private final BatchJdbcOperations batchJdbcOperations;
private final NamedParameterJdbcOperations jdbcOperations;
private final SqlIdentifier idColumn;
IdGeneratingBatchInsertStrategy(InsertStrategy insertStrategy, Dialect dialect,
BatchJdbcOperations batchJdbcOperations, @Nullable SqlIdentifier idColumn) {
NamedParameterJdbcOperations jdbcOperations, @Nullable SqlIdentifier idColumn) {
this.insertStrategy = insertStrategy;
this.dialect = dialect;
this.batchJdbcOperations = batchJdbcOperations;
this.jdbcOperations = jdbcOperations;
this.idColumn = idColumn;
}
@@ -66,12 +69,12 @@ class IdGeneratingBatchInsertStrategy implements BatchInsertStrategy {
String[] keyColumnNames = getKeyColumnNames();
if (keyColumnNames.length == 0) {
batchJdbcOperations.batchUpdate(sql, sqlParameterSources, holder);
jdbcOperations.batchUpdate(sql, sqlParameterSources, holder);
} else {
batchJdbcOperations.batchUpdate(sql, sqlParameterSources, holder, keyColumnNames);
jdbcOperations.batchUpdate(sql, sqlParameterSources, holder, keyColumnNames);
}
} else {
batchJdbcOperations.batchUpdate(sql, sqlParameterSources, holder);
jdbcOperations.batchUpdate(sql, sqlParameterSources, holder);
}
Object[] ids = new Object[sqlParameterSources.length];
List<Map<String, Object>> keyList = holder.getKeyList();

View File

@@ -27,20 +27,30 @@ import org.springframework.lang.Nullable;
* whether the insert is expected to generate ids.
*
* @author Chirag Tailor
* @author Jens Schauder
* @since 2.4
*/
public class InsertStrategyFactory {
private final NamedParameterJdbcOperations namedParameterJdbcOperations;
private final BatchJdbcOperations batchJdbcOperations;
private final NamedParameterJdbcOperations jdbcOperations;
private final Dialect dialect;
public InsertStrategyFactory(NamedParameterJdbcOperations jdbcOperations, Dialect dialect) {
this.jdbcOperations = jdbcOperations;
this.dialect = dialect;
}
/**
* Constructor with additional {@link BatchJdbcOperations} constructor.
*
* @deprecated Use the {@link InsertStrategyFactory#InsertStrategyFactory(NamedParameterJdbcOperations, Dialect)}
* instead.
*/
@Deprecated(since = "3.2")
public InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations,
BatchJdbcOperations batchJdbcOperations, Dialect dialect) {
this.namedParameterJdbcOperations = namedParameterJdbcOperations;
this.batchJdbcOperations = batchJdbcOperations;
this.dialect = dialect;
this(namedParameterJdbcOperations, dialect);
}
/**
@@ -52,9 +62,9 @@ public class InsertStrategyFactory {
InsertStrategy insertStrategy(IdValueSource idValueSource, @Nullable SqlIdentifier idColumn) {
if (IdValueSource.GENERATED.equals(idValueSource)) {
return new IdGeneratingInsertStrategy(dialect, namedParameterJdbcOperations, idColumn);
return new IdGeneratingInsertStrategy(dialect, jdbcOperations, idColumn);
}
return new DefaultInsertStrategy(namedParameterJdbcOperations);
return new DefaultInsertStrategy(jdbcOperations);
}
/**
@@ -66,11 +76,10 @@ public class InsertStrategyFactory {
BatchInsertStrategy batchInsertStrategy(IdValueSource idValueSource, @Nullable SqlIdentifier idColumn) {
if (IdValueSource.GENERATED.equals(idValueSource)) {
return new IdGeneratingBatchInsertStrategy(
new IdGeneratingInsertStrategy(dialect, namedParameterJdbcOperations, idColumn), dialect, batchJdbcOperations,
idColumn);
return new IdGeneratingBatchInsertStrategy(new IdGeneratingInsertStrategy(dialect, jdbcOperations, idColumn),
dialect, jdbcOperations, idColumn);
}
return new DefaultBatchInsertStrategy(namedParameterJdbcOperations);
return new DefaultBatchInsertStrategy(jdbcOperations);
}
private static class DefaultInsertStrategy implements InsertStrategy {

View File

@@ -89,8 +89,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context, converter, dialect);
SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(context, converter);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(operations,
new BatchJdbcOperations(operations.getJdbcOperations()), dialect);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(operations, dialect);
DataAccessStrategy defaultDataAccessStrategy = new DataAccessStrategyFactory( //
sqlGeneratorSource, //

View File

@@ -209,7 +209,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context, jdbcConverter, dialect);
DataAccessStrategyFactory factory = new DataAccessStrategyFactory(sqlGeneratorSource, jdbcConverter, operations,
new SqlParametersFactory(context, jdbcConverter),
new InsertStrategyFactory(operations, new BatchJdbcOperations(operations.getJdbcOperations()), dialect));
new InsertStrategyFactory(operations, dialect));
return factory.create();
}

View File

@@ -21,7 +21,6 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.jdbc.core.convert.BatchJdbcOperations;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory;
import org.springframework.data.jdbc.core.convert.InsertStrategyFactory;
@@ -179,8 +178,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(this.mappingContext, this.converter,
this.dialect);
SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(this.mappingContext, this.converter);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(this.operations,
new BatchJdbcOperations(this.operations.getJdbcOperations()), this.dialect);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(this.operations, this.dialect);
DataAccessStrategyFactory factory = new DataAccessStrategyFactory(sqlGeneratorSource, this.converter,
this.operations, sqlParametersFactory, insertStrategyFactory);

View File

@@ -29,6 +29,7 @@ import org.springframework.data.relational.core.dialect.LimitClause;
import org.springframework.data.relational.core.dialect.LockClause;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.KeyHolder;
@@ -41,7 +42,7 @@ class IdGeneratingBatchInsertStrategyTest {
SqlIdentifier idColumn = SqlIdentifier.quoted("id");
IdentifierProcessing identifierProcessing = IdentifierProcessing.ANSI;
BatchJdbcOperations batchJdbcOperations = mock(BatchJdbcOperations.class);
NamedParameterJdbcOperations jdbcOperations = mock(NamedParameterJdbcOperations.class);
InsertStrategy insertStrategy = mock(InsertStrategy.class);
String sql = "some sql";
SqlParameterSource[] sqlParameterSources = new SqlParameterSource[] { new SqlIdentifierParameterSource() };
@@ -50,7 +51,7 @@ class IdGeneratingBatchInsertStrategyTest {
void insertsSequentially_whenIdGenerationForBatchOperationsNotSupported() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, true, false), batchJdbcOperations, idColumn);
createDialect(identifierProcessing, true, false), jdbcOperations, idColumn);
SqlIdentifierParameterSource sqlParameterSource1 = new SqlIdentifierParameterSource();
sqlParameterSource1.addValue(SqlIdentifier.quoted("property1"), "value1");
@@ -72,11 +73,11 @@ class IdGeneratingBatchInsertStrategyTest {
void insertsWithKeyHolderAndKeyColumnNames_whenDriverRequiresKeyColumnNames() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, true, true), batchJdbcOperations, idColumn);
createDialect(identifierProcessing, true, true), jdbcOperations, idColumn);
batchInsertStrategy.execute(sql, sqlParameterSources);
verify(batchJdbcOperations).batchUpdate(eq(sql), eq(sqlParameterSources), any(KeyHolder.class),
verify(jdbcOperations).batchUpdate(eq(sql), eq(sqlParameterSources), any(KeyHolder.class),
eq(new String[] { idColumn.getReference() }));
}
@@ -84,29 +85,29 @@ class IdGeneratingBatchInsertStrategyTest {
void insertsWithKeyHolder_whenDriverRequiresKeyColumnNames_butIdColumnIsNull() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, true, true), batchJdbcOperations, null);
createDialect(identifierProcessing, true, true), jdbcOperations, null);
batchInsertStrategy.execute(sql, sqlParameterSources);
verify(batchJdbcOperations).batchUpdate(eq(sql), eq(sqlParameterSources), any(KeyHolder.class));
verify(jdbcOperations).batchUpdate(eq(sql), eq(sqlParameterSources), any(KeyHolder.class));
}
@Test
void insertsWithKeyHolder_whenDriverDoesNotRequireKeyColumnNames() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
createDialect(identifierProcessing, false, true), jdbcOperations, idColumn);
batchInsertStrategy.execute(sql, sqlParameterSources);
verify(batchJdbcOperations).batchUpdate(eq(sql), eq(sqlParameterSources), any(KeyHolder.class));
verify(jdbcOperations).batchUpdate(eq(sql), eq(sqlParameterSources), any(KeyHolder.class));
}
@Test
void insertsWithKeyHolder_returningKey_whenThereIsOnlyOne() {
Long idValue = 123L;
when(batchJdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
when(jdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
@@ -115,7 +116,7 @@ class IdGeneratingBatchInsertStrategyTest {
return null;
});
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
createDialect(identifierProcessing, false, true), jdbcOperations, idColumn);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -126,7 +127,7 @@ class IdGeneratingBatchInsertStrategyTest {
void insertsWithKeyHolder_returningKeyMatchingIdColumn_whenKeyHolderContainsMultipleKeysPerRecord() {
Long idValue = 123L;
when(batchJdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
when(jdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
@@ -136,7 +137,7 @@ class IdGeneratingBatchInsertStrategyTest {
return null;
});
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
createDialect(identifierProcessing, false, true), jdbcOperations, idColumn);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -147,7 +148,7 @@ class IdGeneratingBatchInsertStrategyTest {
void insertsWithKeyHolder_returningNull__whenKeyHolderContainsMultipleKeysPerRecord_butIdColumnIsNull() {
Long idValue = 123L;
when(batchJdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
when(jdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
@@ -157,7 +158,7 @@ class IdGeneratingBatchInsertStrategyTest {
return null;
});
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, null);
createDialect(identifierProcessing, false, true), jdbcOperations, null);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -169,7 +170,7 @@ class IdGeneratingBatchInsertStrategyTest {
void insertsWithKeyHolder_returningNull_whenKeyHolderHasNoKeys() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
createDialect(identifierProcessing, false, true), jdbcOperations, idColumn);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);

View File

@@ -32,9 +32,8 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
class InsertStrategyFactoryTest {
NamedParameterJdbcOperations namedParameterJdbcOperations = mock(NamedParameterJdbcOperations.class);
BatchJdbcOperations batchJdbcOperations = mock(BatchJdbcOperations.class);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(namedParameterJdbcOperations,
batchJdbcOperations, AnsiDialect.INSTANCE);
AnsiDialect.INSTANCE);
String sql = "some sql";
SqlParameterSource sqlParameterSource = new SqlIdentifierParameterSource();

View File

@@ -15,6 +15,16 @@
*/
package org.springframework.data.jdbc.repository;
import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.groups.Tuple.tuple;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
@@ -23,7 +33,15 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.convert.*;
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy;
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
import org.springframework.data.jdbc.core.convert.DelegatingDataAccessStrategy;
import org.springframework.data.jdbc.core.convert.InsertStrategyFactory;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
import org.springframework.data.jdbc.core.convert.SqlParametersFactory;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository;
@@ -48,16 +66,6 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.lang.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.groups.Tuple.tuple;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
/**
* Unit tests for application events via {@link SimpleJdbcRepository}.
*
@@ -90,8 +98,7 @@ class SimpleJdbcRepositoryEventsUnitTests {
new DefaultJdbcTypeFactory(operations.getJdbcOperations()), dialect.getIdentifierProcessing());
SqlGeneratorSource generatorSource = new SqlGeneratorSource(context, converter, dialect);
SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(context, converter);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(operations,
new BatchJdbcOperations(operations.getJdbcOperations()), dialect);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(operations, dialect);
this.dataAccessStrategy = spy(new DefaultDataAccessStrategy(generatorSource, context, converter, operations,
sqlParametersFactory, insertStrategyFactory));
@@ -299,8 +306,7 @@ class SimpleJdbcRepositoryEventsUnitTests {
extends CrudRepository<DummyEntity, Long>, PagingAndSortingRepository<DummyEntity, Long> {}
static final class DummyEntity {
@Id
private final Long id;
@Id private final Long id;
public DummyEntity(Long id) {
this.id = id;
@@ -311,12 +317,15 @@ class SimpleJdbcRepositoryEventsUnitTests {
}
public boolean equals(final Object o) {
if (o == this) return true;
if (!(o instanceof DummyEntity)) return false;
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;
if (this$id == null ? other$id != null : !this$id.equals(other$id))
return false;
return true;
}

View File

@@ -34,7 +34,6 @@ import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.BatchJdbcOperations;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory;
import org.springframework.data.jdbc.core.convert.InsertStrategyFactory;
@@ -169,7 +168,7 @@ public class EnableJdbcRepositoriesIntegrationTests {
RelationalMappingContext context, JdbcConverter converter, Dialect dialect) {
return new DataAccessStrategyFactory(new SqlGeneratorSource(context, converter, dialect), converter, template,
new SqlParametersFactory(context, converter),
new InsertStrategyFactory(template, new BatchJdbcOperations(template.getJdbcOperations()), dialect)).create();
new InsertStrategyFactory(template, dialect)).create();
}
@Bean

View File

@@ -110,7 +110,7 @@ public class TestConfiguration {
return new DataAccessStrategyFactory(new SqlGeneratorSource(context, converter, dialect), converter,
template, new SqlParametersFactory(context, converter),
new InsertStrategyFactory(template, new BatchJdbcOperations(template.getJdbcOperations()), dialect)).create();
new InsertStrategyFactory(template, dialect)).create();
}
@Bean("jdbcMappingContext")