Skip to content

Commit efaebda

Browse files
committed
Refactor AggregateReader lifecycle.
Use a single instance as there is no entity-specific state attached to AggregateReader.
1 parent a5107cd commit efaebda

File tree

3 files changed

+43
-55
lines changed

3 files changed

+43
-55
lines changed

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

+33-35
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,24 @@
4848
* intermediate {@link RowDocumentResultSetExtractor RowDocument} and mapped via
4949
* {@link org.springframework.data.relational.core.conversion.RelationalConverter#read(Class, RowDocument)}.
5050
*
51-
* @param <T> the type of aggregate produced by this reader.
5251
* @author Jens Schauder
5352
* @author Mark Paluch
5453
* @since 3.2
5554
*/
56-
class AggregateReader<T> implements PathToColumnMapping {
55+
class AggregateReader implements PathToColumnMapping {
5756

58-
private final RelationalPersistentEntity<T> aggregate;
59-
private final Table table;
57+
private final AliasFactory aliasFactory;
6058
private final SqlGenerator sqlGenerator;
6159
private final JdbcConverter converter;
6260
private final NamedParameterJdbcOperations jdbcTemplate;
63-
private final AliasFactory aliasFactory;
6461
private final RowDocumentResultSetExtractor extractor;
6562

66-
AggregateReader(Dialect dialect, JdbcConverter converter, AliasFactory aliasFactory,
67-
NamedParameterJdbcOperations jdbcTemplate, RelationalPersistentEntity<T> aggregate) {
63+
AggregateReader(Dialect dialect, JdbcConverter converter, NamedParameterJdbcOperations jdbcTemplate) {
6864

65+
this.aliasFactory = new AliasFactory();
6966
this.converter = converter;
70-
this.aggregate = aggregate;
7167
this.jdbcTemplate = jdbcTemplate;
72-
this.table = Table.create(aggregate.getQualifiedTableName());
7368
this.sqlGenerator = new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect);
74-
this.aliasFactory = aliasFactory;
7569
this.extractor = new RowDocumentResultSetExtractor(converter.getMappingContext(), this);
7670
}
7771

@@ -93,54 +87,55 @@ public String keyColumn(AggregatePath path) {
9387
}
9488

9589
@Nullable
96-
public T findById(Object id) {
90+
public <T> T findById(Object id, RelationalPersistentEntity<T> entity) {
9791

98-
Query query = Query.query(Criteria.where(aggregate.getRequiredIdProperty().getName()).is(id)).limit(1);
92+
Query query = Query.query(Criteria.where(entity.getRequiredIdProperty().getName()).is(id)).limit(1);
9993

100-
return findOne(query);
94+
return findOne(query, entity);
10195
}
10296

10397
@Nullable
104-
public T findOne(Query query) {
105-
return doFind(query, this::extractZeroOrOne);
98+
public <T> T findOne(Query query, RelationalPersistentEntity<T> entity) {
99+
return doFind(query, entity, rs -> extractZeroOrOne(rs, entity));
106100
}
107101

108-
public List<T> findAllById(Iterable<?> ids) {
102+
public <T> List<T> findAllById(Iterable<?> ids, RelationalPersistentEntity<T> entity) {
109103

110104
Collection<?> identifiers = ids instanceof Collection<?> idl ? idl : Streamable.of(ids).toList();
111-
Query query = Query.query(Criteria.where(aggregate.getRequiredIdProperty().getName()).in(identifiers));
105+
Query query = Query.query(Criteria.where(entity.getRequiredIdProperty().getName()).in(identifiers));
112106

113-
return findAll(query);
107+
return findAll(query, entity);
114108
}
115109

116110
@SuppressWarnings("ConstantConditions")
117-
public List<T> findAll() {
118-
return jdbcTemplate.query(sqlGenerator.findAll(aggregate), this::extractAll);
111+
public <T> List<T> findAll(RelationalPersistentEntity<T> entity) {
112+
return jdbcTemplate.query(sqlGenerator.findAll(entity),
113+
(ResultSetExtractor<? extends List<T>>) rs -> extractAll(rs, entity));
119114
}
120115

121-
public List<T> findAll(Query query) {
122-
return doFind(query, this::extractAll);
116+
public <T> List<T> findAll(Query query, RelationalPersistentEntity<T> entity) {
117+
return doFind(query, entity, rs -> extractAll(rs, entity));
123118
}
124119

125120
@SuppressWarnings("ConstantConditions")
126-
private <R> R doFind(Query query, ResultSetExtractor<R> extractor) {
121+
private <T, R> R doFind(Query query, RelationalPersistentEntity<T> entity, ResultSetExtractor<R> extractor) {
127122

128123
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
129-
Condition condition = createCondition(query, parameterSource);
130-
String sql = sqlGenerator.findAll(aggregate, condition);
124+
Condition condition = createCondition(query, parameterSource, entity);
125+
String sql = sqlGenerator.findAll(entity, condition);
131126

132127
return jdbcTemplate.query(sql, parameterSource, extractor);
133128
}
134129

135130
@Nullable
136-
private Condition createCondition(Query query, MapSqlParameterSource parameterSource) {
131+
private Condition createCondition(Query query, MapSqlParameterSource parameterSource,
132+
RelationalPersistentEntity<?> entity) {
137133

138134
QueryMapper queryMapper = new QueryMapper(converter);
139135

140136
Optional<CriteriaDefinition> criteria = query.getCriteria();
141-
return criteria
142-
.map(criteriaDefinition -> queryMapper.getMappedObject(parameterSource, criteriaDefinition, table, aggregate))
143-
.orElse(null);
137+
return criteria.map(criteriaDefinition -> queryMapper.getMappedObject(parameterSource, criteriaDefinition,
138+
Table.create(entity.getQualifiedTableName()), entity)).orElse(null);
144139
}
145140

146141
/**
@@ -152,12 +147,13 @@ private Condition createCondition(Query query, MapSqlParameterSource parameterSo
152147
* @return a {@code List} of aggregates, fully converted.
153148
* @throws SQLException on underlying JDBC errors.
154149
*/
155-
private List<T> extractAll(ResultSet rs) throws SQLException {
150+
private <T> List<T> extractAll(ResultSet rs, RelationalPersistentEntity<T> entity) throws SQLException {
156151

157-
Iterator<RowDocument> iterate = extractor.iterate(aggregate, rs);
152+
Iterator<RowDocument> iterate = extractor.iterate(entity, rs);
158153
List<T> resultList = new ArrayList<>();
154+
159155
while (iterate.hasNext()) {
160-
resultList.add(converter.read(aggregate.getType(), iterate.next()));
156+
resultList.add(converter.read(entity.getType(), iterate.next()));
161157
}
162158

163159
return resultList;
@@ -175,17 +171,19 @@ private List<T> extractAll(ResultSet rs) throws SQLException {
175171
* @throws IncorrectResultSizeDataAccessException when the conversion yields more than one instance.
176172
*/
177173
@Nullable
178-
private T extractZeroOrOne(ResultSet rs) throws SQLException {
174+
private <T> T extractZeroOrOne(ResultSet rs, RelationalPersistentEntity<T> entity) throws SQLException {
175+
176+
Iterator<RowDocument> iterate = extractor.iterate(entity, rs);
179177

180-
Iterator<RowDocument> iterate = extractor.iterate(aggregate, rs);
181178
if (iterate.hasNext()) {
182179

183180
RowDocument object = iterate.next();
184181
if (iterate.hasNext()) {
185182
throw new IncorrectResultSizeDataAccessException(1);
186183
}
187-
return converter.read(aggregate.getType(), object);
184+
return converter.read(entity.getType(), object);
188185
}
186+
189187
return null;
190188
}
191189

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

+9-18
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2626
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2727
import org.springframework.data.relational.core.query.Query;
28-
import org.springframework.data.relational.core.sqlgeneration.AliasFactory;
2928
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
30-
import org.springframework.util.ConcurrentLruCache;
3129

3230
/**
3331
* A {@link ReadingDataAccessStrategy} that uses an {@link AggregateReader} to load entities with a single query.
@@ -39,31 +37,28 @@
3937
class SingleQueryDataAccessStrategy implements ReadingDataAccessStrategy {
4038

4139
private final RelationalMappingContext mappingContext;
42-
private final AliasFactory aliasFactory;
43-
private final ConcurrentLruCache<RelationalPersistentEntity<?>, AggregateReader<?>> readerCache;
40+
private final AggregateReader aggregateReader;
4441

4542
public SingleQueryDataAccessStrategy(Dialect dialect, JdbcConverter converter,
4643
NamedParameterJdbcOperations jdbcTemplate) {
4744

4845
this.mappingContext = converter.getMappingContext();
49-
this.aliasFactory = new AliasFactory();
50-
this.readerCache = new ConcurrentLruCache<>(256,
51-
entity -> new AggregateReader<>(dialect, converter, aliasFactory, jdbcTemplate, entity));
46+
this.aggregateReader = new AggregateReader(dialect, converter, jdbcTemplate);
5247
}
5348

5449
@Override
5550
public <T> T findById(Object id, Class<T> domainType) {
56-
return getReader(domainType).findById(id);
51+
return aggregateReader.findById(id, getPersistentEntity(domainType));
5752
}
5853

5954
@Override
6055
public <T> List<T> findAll(Class<T> domainType) {
61-
return getReader(domainType).findAll();
56+
return aggregateReader.findAll(getPersistentEntity(domainType));
6257
}
6358

6459
@Override
6560
public <T> List<T> findAllById(Iterable<?> ids, Class<T> domainType) {
66-
return getReader(domainType).findAllById(ids);
61+
return aggregateReader.findAllById(ids, getPersistentEntity(domainType));
6762
}
6863

6964
@Override
@@ -78,12 +73,12 @@ public <T> List<T> findAll(Class<T> domainType, Pageable pageable) {
7873

7974
@Override
8075
public <T> Optional<T> findOne(Query query, Class<T> domainType) {
81-
return Optional.ofNullable(getReader(domainType).findOne(query));
76+
return Optional.ofNullable(aggregateReader.findOne(query, getPersistentEntity(domainType)));
8277
}
8378

8479
@Override
8580
public <T> List<T> findAll(Query query, Class<T> domainType) {
86-
return getReader(domainType).findAll(query);
81+
return aggregateReader.findAll(query, getPersistentEntity(domainType));
8782
}
8883

8984
@Override
@@ -92,11 +87,7 @@ public <T> List<T> findAll(Query query, Class<T> domainType, Pageable pageable)
9287
}
9388

9489
@SuppressWarnings("unchecked")
95-
private <T> AggregateReader<T> getReader(Class<T> domainType) {
96-
97-
RelationalPersistentEntity<T> persistentEntity = (RelationalPersistentEntity<T>) mappingContext
98-
.getRequiredPersistentEntity(domainType);
99-
100-
return (AggregateReader<T>) readerCache.get(persistentEntity);
90+
private <T> RelationalPersistentEntity<T> getPersistentEntity(Class<T> domainType) {
91+
return (RelationalPersistentEntity<T>) mappingContext.getRequiredPersistentEntity(domainType);
10192
}
10293
}

spring-data-relational/src/jmh/java/org/springframework/data/relational/core/sqlgeneration/SingleQuerySqlGeneratorBenchmark.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ public class SingleQuerySqlGeneratorBenchmark extends BenchmarkSettings {
3838

3939
@Benchmark
4040
public String findAll(StateHolder state) {
41-
return new SingleQuerySqlGenerator(state.context, state.aliasFactory, PostgresDialect.INSTANCE,
42-
state.persistentEntity).findAll(null);
41+
return new SingleQuerySqlGenerator(state.context, state.aliasFactory, PostgresDialect.INSTANCE).findAll(state.persistentEntity, null);
4342
}
4443

4544
@State(Scope.Benchmark)

0 commit comments

Comments
 (0)