18
18
import jakarta .persistence .EntityManager ;
19
19
import jakarta .persistence .Query ;
20
20
21
+ import java .util .Objects ;
22
+
21
23
import org .springframework .data .domain .Pageable ;
22
24
import org .springframework .data .domain .Sort ;
23
25
import org .springframework .data .jpa .repository .QueryRewriter ;
28
30
import org .springframework .expression .spel .standard .SpelExpressionParser ;
29
31
import org .springframework .lang .Nullable ;
30
32
import org .springframework .util .Assert ;
33
+ import org .springframework .util .ConcurrentLruCache ;
31
34
32
35
/**
33
36
* Base class for {@link String} based JPA queries.
40
43
* @author Mark Paluch
41
44
* @author Diego Krupitza
42
45
* @author Greg Turnquist
46
+ * @author Christoph Strobl
43
47
*/
44
48
abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
45
49
@@ -49,6 +53,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
49
53
private final SpelExpressionParser parser ;
50
54
private final QueryParameterSetter .QueryMetadataCache metadataCache = new QueryParameterSetter .QueryMetadataCache ();
51
55
private final QueryRewriter queryRewriter ;
56
+ private ConcurrentLruCache <CachableQuery , String > queryCache = new ConcurrentLruCache <>(100 , this ::applySorting );
52
57
53
58
/**
54
59
* Creates a new {@link AbstractStringBasedJpaQuery} from the given {@link JpaQueryMethod}, {@link EntityManager} and
@@ -106,16 +111,8 @@ public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
106
111
return parameterBinder .get ().bindAndPrepare (query , metadata , accessor );
107
112
}
108
113
109
- private String applySortingIfNecessary (DeclaredQuery query , Sort sort ) {
110
-
111
- if (sort .isUnsorted ()) {
112
- return query .getQueryString ();
113
- }
114
- return applySorting (query , sort );
115
- }
116
-
117
114
protected String applySorting (DeclaredQuery query , Sort sort ) {
118
- return QueryEnhancerFactory . forQuery ( query ). applySorting ( sort , query . getAlias ( ));
115
+ return queryCache . get ( new CachableQuery ( query , sort ));
119
116
}
120
117
121
118
@ Override
@@ -191,4 +188,77 @@ protected String potentiallyRewriteQuery(String originalQuery, Sort sort, @Nulla
191
188
? queryRewriter .rewrite (originalQuery , pageable ) //
192
189
: queryRewriter .rewrite (originalQuery , sort );
193
190
}
191
+
192
+ String applySorting (CachableQuery cachableQuery ) {
193
+
194
+ return QueryEnhancerFactory .forQuery (cachableQuery .getDeclaredQuery ()).applySorting (cachableQuery .getSort (),
195
+ cachableQuery .getAlias ());
196
+ }
197
+
198
+ private String applySortingIfNecessary (DeclaredQuery query , Sort sort ) {
199
+
200
+ if (sort .isUnsorted ()) {
201
+ return query .getQueryString ();
202
+ }
203
+ return applySorting (query , sort );
204
+ }
205
+
206
+ /**
207
+ * Value object with optimized {@link Object#equals(Object)} to cache a query based on its query string and
208
+ * {@link Sort sorting}.
209
+ *
210
+ * @since 3.2.3
211
+ * @author Christoph Strobl
212
+ */
213
+ static class CachableQuery {
214
+
215
+ private DeclaredQuery declaredQuery ;
216
+ private final String queryString ;
217
+ private final Sort sort ;
218
+
219
+ CachableQuery (DeclaredQuery query , Sort sort ) {
220
+
221
+ this .declaredQuery = query ;
222
+ this .queryString = query .getQueryString ();
223
+ this .sort = sort ;
224
+ }
225
+
226
+ DeclaredQuery getDeclaredQuery () {
227
+ return declaredQuery ;
228
+ }
229
+
230
+ Sort getSort () {
231
+ return sort ;
232
+ }
233
+
234
+ String getAlias () {
235
+ return declaredQuery .getAlias ();
236
+ }
237
+
238
+ @ Override
239
+ public boolean equals (Object o ) {
240
+
241
+ if (this == o ) {
242
+ return true ;
243
+ }
244
+ if (o == null || getClass () != o .getClass ()) {
245
+ return false ;
246
+ }
247
+
248
+ CachableQuery that = (CachableQuery ) o ;
249
+
250
+ if (!Objects .equals (queryString , that .queryString )) {
251
+ return false ;
252
+ }
253
+ return Objects .equals (sort , that .sort );
254
+ }
255
+
256
+ @ Override
257
+ public int hashCode () {
258
+
259
+ int result = queryString != null ? queryString .hashCode () : 0 ;
260
+ result = 31 * result + (sort != null ? sort .hashCode () : 0 );
261
+ return result ;
262
+ }
263
+ }
194
264
}
0 commit comments