Skip to content

Commit 989a2b0

Browse files
rPramlnPraml
authored andcommitted
NOPR - NEW: QueryCache support for DTO queries
1 parent 2353bc2 commit 989a2b0

11 files changed

Lines changed: 142 additions & 60 deletions

File tree

ebean-core/src/main/java/io/ebeaninternal/api/HashQuery.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ public final class HashQuery {
77

88
private final CQueryPlanKey planHash;
99
private final BindValuesKey bindValuesKey;
10+
private final Class<?> dtoType;
1011

1112
/**
1213
* Create the HashQuery.
1314
*/
14-
public HashQuery(CQueryPlanKey planHash, BindValuesKey bindValuesKey) {
15+
public HashQuery(CQueryPlanKey planHash, BindValuesKey bindValuesKey, Class<?> dtoType) {
1516
this.planHash = planHash;
1617
this.bindValuesKey = bindValuesKey;
18+
this.dtoType = dtoType;
1719
}
1820

1921
@Override
@@ -25,6 +27,7 @@ public String toString() {
2527
public int hashCode() {
2628
int hc = 92821 * planHash.hashCode();
2729
hc = 92821 * hc + bindValuesKey.hashCode();
30+
hc = 92821 * hc + dtoType.hashCode();
2831
return hc;
2932
}
3033

@@ -37,6 +40,6 @@ public boolean equals(Object obj) {
3740
return false;
3841
}
3942
HashQuery e = (HashQuery) obj;
40-
return e.bindValuesKey.equals(bindValuesKey) && e.planHash.equals(planHash);
43+
return e.bindValuesKey.equals(bindValuesKey) && e.planHash.equals(planHash) && e.dtoType.equals(dtoType);
4144
}
4245
}

ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,11 @@ public static TemporalMode of(SpiQuery<?> query) {
877877
*/
878878
void setManualId();
879879

880+
/**
881+
* Set the DTO type, that should be part of the queryHash.
882+
*/
883+
void setDtoType(Class<?> dtoType);
884+
880885
/**
881886
* Set default select clauses where none have been explicitly defined.
882887
*/

ebean-core/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private String limitOffset(String sql) {
132132
/**
133133
* Prepare and execute the SQL using the Binder.
134134
*/
135-
public void executeSql(Binder binder, SpiQuery.Type type) throws SQLException {
135+
public void executeSql(Binder binder) throws SQLException {
136136
startNano = System.nanoTime();
137137
executeAsSql(binder);
138138
}

ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ public <T> DtoQuery<T> createNamedDtoQuery(Class<T> dtoType, String namedQuery)
898898
@Override
899899
public <T> DtoQuery<T> findDto(Class<T> dtoType, SpiQuery<?> ormQuery) {
900900
DtoBeanDescriptor<T> descriptor = dtoBeanManager.descriptor(dtoType);
901+
ormQuery.setDtoType(dtoType);
901902
return new DefaultDtoQuery<>(this, descriptor, ormQuery);
902903
}
903904

@@ -940,6 +941,18 @@ public <T> T find(Class<T> beanType, Object id, @Nullable Transaction transactio
940941
return findId(query);
941942
}
942943

944+
<T> DtoQueryRequest<T> createDtoQueryRequest(Type type, SpiDtoQuery<T> query) {
945+
SpiQuery<?> ormQuery = query.ormQuery();
946+
if (ormQuery != null) {
947+
ormQuery.setType(type);
948+
ormQuery.setManualId();
949+
SpiOrmQueryRequest<?> ormRequest = createQueryRequest(type, ormQuery);
950+
return new DtoQueryRequest<>(this, dtoQueryEngine, query, ormRequest);
951+
} else {
952+
return new DtoQueryRequest<>(this, dtoQueryEngine, query, null);
953+
}
954+
}
955+
943956
<T> SpiOrmQueryRequest<T> createQueryRequest(Type type, SpiQuery<T> query) {
944957
SpiOrmQueryRequest<T> request = buildQueryRequest(type, query);
945958
request.prepareQuery();
@@ -1544,7 +1557,7 @@ public <T> T findSingleAttribute(SpiSqlQuery query, Class<T> cls) {
15441557

15451558
@Override
15461559
public <T> void findDtoEach(SpiDtoQuery<T> query, Consumer<T> consumer) {
1547-
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
1560+
DtoQueryRequest<T> request = createDtoQueryRequest(Type.ITERATE, query);
15481561
try {
15491562
request.initTransIfRequired();
15501563
request.findEach(consumer);
@@ -1555,7 +1568,7 @@ public <T> void findDtoEach(SpiDtoQuery<T> query, Consumer<T> consumer) {
15551568

15561569
@Override
15571570
public <T> void findDtoEach(SpiDtoQuery<T> query, int batch, Consumer<List<T>> consumer) {
1558-
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
1571+
DtoQueryRequest<T> request = createDtoQueryRequest(Type.ITERATE, query);
15591572
try {
15601573
request.initTransIfRequired();
15611574
request.findEach(batch, consumer);
@@ -1566,7 +1579,7 @@ public <T> void findDtoEach(SpiDtoQuery<T> query, int batch, Consumer<List<T>> c
15661579

15671580
@Override
15681581
public <T> void findDtoEachWhile(SpiDtoQuery<T> query, Predicate<T> consumer) {
1569-
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
1582+
DtoQueryRequest<T> request = createDtoQueryRequest(Type.ITERATE, query);
15701583
try {
15711584
request.initTransIfRequired();
15721585
request.findEachWhile(consumer);
@@ -1577,7 +1590,7 @@ public <T> void findDtoEachWhile(SpiDtoQuery<T> query, Predicate<T> consumer) {
15771590

15781591
@Override
15791592
public <T> QueryIterator<T> findDtoIterate(SpiDtoQuery<T> query) {
1580-
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
1593+
DtoQueryRequest<T> request = createDtoQueryRequest(Type.ITERATE, query);
15811594
try {
15821595
request.initTransIfRequired();
15831596
return request.findIterate();
@@ -1594,7 +1607,11 @@ public <T> Stream<T> findDtoStream(SpiDtoQuery<T> query) {
15941607

15951608
@Override
15961609
public <T> List<T> findDtoList(SpiDtoQuery<T> query) {
1597-
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
1610+
DtoQueryRequest<T> request = createDtoQueryRequest(Type.LIST, query);
1611+
List<T> ret = request.getFromQueryCache();
1612+
if (ret != null) {
1613+
return ret;
1614+
}
15981615
try {
15991616
request.initTransIfRequired();
16001617
return request.findList();
@@ -1606,13 +1623,7 @@ public <T> List<T> findDtoList(SpiDtoQuery<T> query) {
16061623
@Nullable
16071624
@Override
16081625
public <T> T findDtoOne(SpiDtoQuery<T> query) {
1609-
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
1610-
try {
1611-
request.initTransIfRequired();
1612-
return extractUnique(request.findList());
1613-
} finally {
1614-
request.endTransIfRequired();
1615-
}
1626+
return extractUnique(findDtoList(query));
16161627
}
16171628

16181629
/**

ebean-core/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import io.ebean.core.type.DataReader;
55
import io.ebeaninternal.api.SpiDtoQuery;
66
import io.ebeaninternal.api.SpiEbeanServer;
7-
import io.ebeaninternal.api.SpiQuery;
87
import io.ebeaninternal.server.dto.DtoColumn;
98
import io.ebeaninternal.server.dto.DtoMappingRequest;
109
import io.ebeaninternal.server.dto.DtoQueryPlan;
@@ -31,33 +30,30 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
3130
private final DtoQueryEngine queryEngine;
3231
private DtoQueryPlan plan;
3332
private DataReader dataReader;
33+
private SpiOrmQueryRequest<?> ormRequest;
3434

35-
DtoQueryRequest(SpiEbeanServer server, DtoQueryEngine engine, SpiDtoQuery<T> query) {
35+
DtoQueryRequest(SpiEbeanServer server, DtoQueryEngine engine, SpiDtoQuery<T> query, SpiOrmQueryRequest<?> ormRequest) {
3636
super(server, query);
3737
this.queryEngine = engine;
3838
this.query = query;
39+
this.ormRequest = ormRequest;
3940
query.obtainLocation();
4041
}
4142

4243
/**
4344
* Prepare and execute the SQL using the Binder.
4445
*/
4546
@Override
46-
public void executeSql(Binder binder, SpiQuery.Type type) throws SQLException {
47+
public void executeSql(Binder binder) throws SQLException {
4748
startNano = System.nanoTime();
48-
SpiQuery<?> ormQuery = query.ormQuery();
49-
if (ormQuery != null) {
50-
ormQuery.setType(type);
51-
ormQuery.setManualId();
52-
53-
query.setCancelableQuery(ormQuery);
49+
if (ormRequest != null) {
5450
// execute the underlying ORM query returning the ResultSet
55-
ormQuery.usingTransaction(transaction);
56-
SpiResultSet result = server.findResultSet(ormQuery);
51+
query.setCancelableQuery(query.ormQuery());
52+
ormRequest.transaction(transaction);
53+
SpiResultSet result = ormRequest.findResultSet();
5754
this.pstmt = result.statement();
58-
this.sql = ormQuery.getGeneratedSql();
59-
setResultSet(result.resultSet(), ormQuery.queryPlanKey());
60-
55+
this.sql = ormRequest.query().getGeneratedSql();
56+
setResultSet(result.resultSet(), ormRequest.query().queryPlanKey());
6157
} else {
6258
// native SQL query execution
6359
executeAsSql(binder);
@@ -156,4 +152,18 @@ static String parseColumn(String columnLabel) {
156152
return columnLabel;
157153
}
158154

155+
public List<T> getFromQueryCache() {
156+
if (ormRequest != null) {
157+
return ormRequest.getFromQueryCache();
158+
} else {
159+
return null;
160+
}
161+
}
162+
163+
public void putToQueryCache(List<T> result) {
164+
if (ormRequest != null && ormRequest.isQueryCachePut()) {
165+
ormRequest.putToQueryCache(result);
166+
}
167+
}
168+
159169
}

ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import io.ebean.meta.MetricVisitor;
99
import io.ebean.metric.MetricFactory;
1010
import io.ebean.metric.TimedMetricMap;
11-
import io.ebeaninternal.api.SpiQuery;
1211
import io.ebeaninternal.server.core.RelationalQueryEngine;
1312
import io.ebeaninternal.server.core.RelationalQueryRequest;
1413
import io.ebeaninternal.server.core.RowReader;
@@ -67,7 +66,7 @@ public void findEach(RelationalQueryRequest request, RowConsumer consumer) {
6766
if (defaultFetchSizeFindEach > 0) {
6867
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
6968
}
70-
request.executeSql(binder, SpiQuery.Type.ITERATE);
69+
request.executeSql(binder);
7170
request.mapEach(consumer);
7271
request.logSummary();
7372

@@ -85,7 +84,7 @@ public <T> void findEach(RelationalQueryRequest request, RowReader<T> reader, Pr
8584
if (defaultFetchSizeFindEach > 0) {
8685
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
8786
}
88-
request.executeSql(binder, SpiQuery.Type.ITERATE);
87+
request.executeSql(binder);
8988
while (request.next()) {
9089
if (!consumer.test(reader.read())) {
9190
break;
@@ -104,7 +103,7 @@ public <T> void findEach(RelationalQueryRequest request, RowReader<T> reader, Pr
104103
@Override
105104
public <T> T findOne(RelationalQueryRequest request, RowMapper<T> mapper) {
106105
try {
107-
request.executeSql(binder, SpiQuery.Type.BEAN);
106+
request.executeSql(binder);
108107
T value = request.mapOne(mapper);
109108
request.logSummary();
110109
return value;
@@ -123,7 +122,7 @@ public <T> List<T> findList(RelationalQueryRequest request, RowReader<T> reader)
123122
if (defaultFetchSizeFindList > 0) {
124123
request.setDefaultFetchBuffer(defaultFetchSizeFindList);
125124
}
126-
request.executeSql(binder, SpiQuery.Type.LIST);
125+
request.executeSql(binder);
127126
List<T> rows = new ArrayList<>();
128127
while (request.next()) {
129128
rows.add(reader.read());
@@ -146,7 +145,7 @@ public <T> T findSingleAttribute(RelationalQueryRequest request, Class<T> cls) {
146145
if (defaultFetchSizeFindList > 0) {
147146
request.setDefaultFetchBuffer(defaultFetchSizeFindList);
148147
}
149-
request.executeSql(binder, SpiQuery.Type.ATTRIBUTE);
148+
request.executeSql(binder);
150149
final DataReader dataReader = binder.createDataReader(request.resultSet());
151150
T value = null;
152151
if (dataReader.next()) {
@@ -171,7 +170,7 @@ public <T> List<T> findSingleAttributeList(RelationalQueryRequest request, Class
171170
if (defaultFetchSizeFindList > 0) {
172171
request.setDefaultFetchBuffer(defaultFetchSizeFindList);
173172
}
174-
request.executeSql(binder, SpiQuery.Type.ATTRIBUTE);
173+
request.executeSql(binder);
175174
final DataReader dataReader = binder.createDataReader(request.resultSet());
176175
List<T> rows = new ArrayList<>();
177176
while (dataReader.next()) {
@@ -196,7 +195,7 @@ public <T> void findSingleAttributeEach(RelationalQueryRequest request, Class<T>
196195
if (defaultFetchSizeFindEach > 0) {
197196
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
198197
}
199-
request.executeSql(binder, SpiQuery.Type.ATTRIBUTE);
198+
request.executeSql(binder);
200199
final DataReader dataReader = binder.createDataReader(request.resultSet());
201200
while (dataReader.next()) {
202201
consumer.accept(scalarType.read(dataReader));

ebean-core/src/main/java/io/ebeaninternal/server/query/DtoQueryEngine.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.ebeaninternal.server.query;
22

33
import io.ebean.QueryIterator;
4-
import io.ebeaninternal.api.SpiQuery;
54
import io.ebeaninternal.server.core.DtoQueryRequest;
65
import io.ebeaninternal.server.persist.Binder;
76
import jakarta.persistence.PersistenceException;
@@ -29,11 +28,12 @@ public <T> List<T> findList(DtoQueryRequest<T> request) {
2928
if (defaultFetchSizeFindList > 0) {
3029
request.setDefaultFetchBuffer(defaultFetchSizeFindList);
3130
}
32-
request.executeSql(binder, SpiQuery.Type.LIST);
31+
request.executeSql(binder);
3332
List<T> rows = new ArrayList<>();
3433
while (request.next()) {
3534
rows.add(request.readNextBean());
3635
}
36+
request.putToQueryCache(rows);
3737
return rows;
3838

3939
} catch (SQLException e) {
@@ -48,27 +48,27 @@ public <T> QueryIterator<T> findIterate(DtoQueryRequest<T> request) {
4848
if (defaultFetchSizeFindEach > 0) {
4949
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
5050
}
51-
request.executeSql(binder, SpiQuery.Type.ITERATE);
51+
request.executeSql(binder);
5252
return new DtoQueryIterator<>(request);
5353
} catch (SQLException e) {
5454
throw new PersistenceException(errMsg(e.getMessage(), request.getSql()), e);
5555
}
5656
}
5757

5858
public <T> void findEach(DtoQueryRequest<T> request, Consumer<T> consumer) {
59-
try {
6059
if (defaultFetchSizeFindEach > 0) {
6160
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
6261
}
63-
request.executeSql(binder, SpiQuery.Type.ITERATE);
64-
while (request.next()) {
65-
consumer.accept(request.readNextBean());
62+
try {
63+
request.executeSql(binder);
64+
while (request.next()) {
65+
consumer.accept(request.readNextBean());
66+
}
67+
} catch (SQLException e) {
68+
throw new PersistenceException(errMsg(e.getMessage(), request.getSql()), e);
69+
} finally {
70+
request.close();
6671
}
67-
} catch (SQLException e) {
68-
throw new PersistenceException(errMsg(e.getMessage(), request.getSql()), e);
69-
} finally {
70-
request.close();
71-
}
7272
}
7373

7474
public <T> void findEach(DtoQueryRequest<T> request, int batchSize, Consumer<List<T>> consumer) {
@@ -77,7 +77,7 @@ public <T> void findEach(DtoQueryRequest<T> request, int batchSize, Consumer<Lis
7777
if (defaultFetchSizeFindEach > 0) {
7878
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
7979
}
80-
request.executeSql(binder, SpiQuery.Type.ITERATE);
80+
request.executeSql(binder);
8181
while (request.next()) {
8282
buffer.add(request.readNextBean());
8383
if (buffer.size() >= batchSize) {
@@ -101,7 +101,7 @@ public <T> void findEachWhile(DtoQueryRequest<T> request, Predicate<T> consumer)
101101
if (defaultFetchSizeFindEach > 0) {
102102
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
103103
}
104-
request.executeSql(binder, SpiQuery.Type.ITERATE);
104+
request.executeSql(binder);
105105
while (request.next()) {
106106
if (!consumer.test(request.readNextBean())) {
107107
break;

ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
163163
private String nativeSql;
164164
private boolean orderById;
165165
private ProfileLocation profileLocation;
166+
private Class<?> dtoType = Object.class; // default: Object saves some null-checks.
166167

167168
public DefaultOrmQuery(BeanDescriptor<T> desc, SpiEbeanServer server, ExpressionFactory expressionFactory) {
168169
this.beanDescriptor = desc;
@@ -1240,7 +1241,7 @@ public final HashQuery queryHash() {
12401241
// so queryPlanHash is calculated well before this method is called
12411242
BindValuesKey bindKey = new BindValuesKey();
12421243
queryBindKey(bindKey);
1243-
return new HashQuery(queryPlanKey, bindKey);
1244+
return new HashQuery(queryPlanKey, bindKey, dtoType);
12441245
}
12451246

12461247
@Override
@@ -1726,6 +1727,11 @@ public final void setManualId() {
17261727
}
17271728
}
17281729

1730+
@Override
1731+
public void setDtoType(Class<?> dtoType) {
1732+
this.dtoType = dtoType;
1733+
}
1734+
17291735
/**
17301736
* return true if user specified to use SQL DISTINCT (effectively excludes id property).
17311737
*/

0 commit comments

Comments
 (0)