Reputation: 1085
I have two classes wiht relation one to many. User
:
@Entity
public class User {
@Id
private Long id;
...
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<Note> notes = new HashSet<>();
...
}
and Note
:
@Entity
public class Note {
@Id
private Long id;
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
...
}
In the UserRepository
I want to override findAll(Pageable<T> va1)
method from PagingAndSortingRepository<T, ID>
to avoid N+1 query problem. Everything works fine, with this code:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Override
@Query(value = "select distinct u from User u left join fetch u.notes")
Page<User> findAll();
}
But when I add pagination:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Override
@Query(value = "select distinct u from User u left join fetch u.notes",
countQuery = "select count(u) from User u")
Page<User> findAll(Pageable page);
}
I see warn in console:
HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
My question is, how to fix it?
Upvotes: 2
Views: 1270
Reputation: 16400
This is a perfect use case for Blaze-Persistence.
Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. The pagination support it comes with handles all of the issues you might encounter.
It also has a Spring Data integration, so you can use the same code like you do now, you only have to add the dependency and do the setup: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-setup
Blaze-Persistence has many different strategies for pagination which you can configure. The default strategy is to inline the query for ids into the main query. Something like this:
select u
from User u
left join fetch u.notes
where u.id IN (
select u2.id
from User u2
order by ...
limit ...
)
order by ...
Upvotes: 0
Reputation: 18430
When you want to join fetch
child with pagination, Hibernate do SQL query without pagination means fetch full resultset. And do pagination in memory.
The easier way to fix this using two query
Code Example
@Query("select u.id from User u")
List<Long> getAllIds(Pageable page);
@Query(value = "select distinct u from User u left join fetch u.notes where u.id IN (:ids)")
List<User> findAll(@Param("ids")List<Long> ids);
Upvotes: 2