Skip to content

Repository.findOne(Specification) & Repository.findOne(Example) fetches all data that matches the predicate with Hibernate #2701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ndestick opened this issue Nov 15, 2022 · 2 comments
Assignees
Labels
status: duplicate A duplicate of another issue

Comments

@ndestick
Copy link

I couldn't find an issue pertaining to the issue laid out here. My apologies in advance if this is a duplicate.

Recently we discovered that the default behavior of Repository.findOne(Specification) and Repository.findOne(Example) fetches all data that matches the Specification or Example even though we only 2 matches are necessary to know whether or not more than one record matches the predicate. This has resulted in one of our services going down due to out-of-memory errors due to too many records matching the predicate. All of which were loaded into memory.

I've already addressed the issue in our own code by overriding the repository base class implementation with a custom implementation that puts a maximum on the amount of records to retrieve, but I do think it is useful to report it here regardless.

We used

  • org.springframework.boot:spring-boot-starter-data-jpa:jar:2.6.9
  • org.springframework.data:spring-data-jpa:jar:2.6.5
  • org.hibernate:hibernate-core:jar:5.6.9.Final

The code below are the implementations present in the SimpleJpaRepository of the methods mentioned earlier. Of particular notice is TypedQuery<?>.getSingleResult(). Which is called without a prior limit being set through TypedQuery<?>.setMaxResults(int). I'm unaware how other library implementations react when calling the TypedQuery<?>.getSingleResult() method without a limit. However, with the hibernate version I'm using this simply results in a select-query with no limit.

        @Override
	public Optional<T> findOne(@Nullable Specification<T> spec) {
		try {
			return Optional.of(getQuery(spec, Sort.unsorted()).getSingleResult());
		} catch (NoResultException e) {
			return Optional.empty();
		}
	}
       
        @Override
	public <S extends T> Optional<S> findOne(Example<S> example) {
		try {
			return Optional.of(getQuery(
                                       new ExampleSpecification<>(example, escapeCharacter), 
                                       example.getProbeType(), 
                                       Sort.unsorted()
                                   ).getSingleResult());
		} catch (NoResultException e) {
			return Optional.empty();
		}
	}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 15, 2022
@gregturn
Copy link
Contributor

gregturn commented Dec 5, 2022

f128375 resolved this issue in 3.0.x (now main). I just backported this fix to 2.7.x and 2.6.x.

Unfortunately, 2.6.x has passed OSS support. While the patch is backported, unless a commercially-paying custom makes a request, no release for that version is presently scheduled. I recommend upgrading to at least Spring Data JPA 2.7.x.

@gregturn gregturn self-assigned this Dec 5, 2022
@christophstrobl
Copy link
Member

duplicate of: #2594

@christophstrobl christophstrobl added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged labels Dec 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

4 participants