-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Given:
A text block query in a JPA repository, which does not use pagination:
@Repository
class MyRepository extends JpaRepository<MyObject, Long> {
@Query("""
SELECT SUM(o.amount)
FROM MyObject o
WHERE o.userId = :userId""")
Optional<Long> sumAmountByUserId(Long userId);
}
Then:
On application startup, when the repository bean is initialized, the query is validated, which includes HQL interpretation. It is stored in hibernate's QueryInterpretationCacheStandardImpl.hqlInterpretationCache
with the raw query as cache key, including spaces and line breaks: "SELECT SUM(o.amount)\nFROM MyObject o\nWHERE o.userId = :userId"
.
On the first execution of the query, it is rewritten to include the pagination and the resulting HQL is interpreted. The rewritten query is identical to the original since there is no additional order clause from pagination, however, UnsortedCachingQuerySortRewriter
removes extra spaces and line breaks. That means that QueryInterpretationCacheStandardImpl
does not recognize the existing query in the interpretation cache, it parses HQL again and stores it with the new cache key "SELECT SUM(o.amount) FROM MyObject o WHERE o.userId = :userId"
.
While this is not preventing the query from being executed properly, this is inefficient.
Possible solutions:
- Sanitize the query before validation on startup. For example,
JpaQueryLookupStrategy.resolveQuery
could sanitize the query string that is read from the annotation. - Apply the
QueryRewriter
to the validated query in theSimpleJpaQuery
constructor. Then we could write our own query rewriter that sanitizes the block, while the default behaviour withIdentityQueryRewriter
would not change.