api를 실행해보면, 에러는 발생하지 않는데, 콘솔창에 어떤 경고 문구가 뜹니다. 이 문제를 발생시킨 코드는 페이지 제일 아래에 첨부!

2024-10-09T16:49:57.674+09:00 WARN 21808 --- [spring-plus] [nio-8080-exec-9] org.hibernate.orm.query : HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory
결론
이 경고가 뜨는 이유는, fetchJoin을 적용하면서 BatchSize까지 적용할 경우, 이런 경고 문구가 뜨는 것입니다.
- fetchJoin은 즉시 로딩을 통해 연관된 데이터를 한 번에 가져오는 방식입니다.
- @BatchSize는 지연 로딩(Lazy Fetch)을 사용하면서 필요할 때마다 연관된 데이터를 배치로 가져오는 방식입니다.
둘을 같이 사용하면 Hibernate는 두 가지 상반된 전략을 적용하려고 하기 때문에 경고가 발생하는 것입니다. 둘 중 하나만 적용해서 쓰게 된다면, 경고문이 뜨지 않게 됩니다.
============================================================================================
문제 있는 코드
아래의 코드는 QueryDsl에서 fetchJoin() 을 사용하고 있고, 엔티티 클래스에서 @BatchSize를 사용하고 있습니다.
이 경우에는 fetchJoin()을 제외하고 @BatchSize만 사용하면서 문제를 해결했습니다.
QueryDsl
@Override
public Page<TodoSearchResponse> searchTodo(Pageable pageable, String title, LocalDateTime startDateTime, LocalDateTime endDateTime, String nickname){
QTodo todo = QTodo.todo;
QManager manager = QManager.manager;
QComment comment = QComment.comment;
QUser user = QUser.user;
List<Todo> todos = queryFactory
.select(todo)
.from(todo)
.leftJoin(todo.managers, manager).fetchJoin() // 여기 있는 .fetchJoin() 를 없애면서 문제 해결
.leftJoin(todo.comments, comment)
.leftJoin(todo.user, user)
.offset(pageable.getOffset())
.where(
titleContains(title),
userNicknameContains(nickname),
todoDateBetween(startDateTime, endDateTime)
)
.groupBy(todo.id)
.orderBy(todo.createdAt.desc())
.limit(pageable.getPageSize())
.fetch();
List<TodoSearchResponse> dtoList = todos.stream()
.map(t -> new TodoSearchResponse(
t.getTitle(),
t.getManagers().size(),
t.getComments().size()))
.collect(Collectors.toList());
return new PageImpl<>(dtoList, pageable, dtoList.size());
}
private BooleanExpression titleContains(String titleKeyword) {
return titleKeyword != null ? todo.title.contains(titleKeyword) : null;
}
private BooleanExpression userNicknameContains(String managerNickname) {
return managerNickname != null ? user.nickname.contains(managerNickname) : null;
}
private BooleanExpression todoDateBetween(LocalDateTime startDate, LocalDateTime endDate) {
return startDate != null && endDate != null ? todo.createdAt.between(startDate, endDate) : null;
}
Todo Entity
package org.example.expert.domain.todo.entity;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.example.expert.domain.comment.entity.Comment;
import org.example.expert.domain.common.entity.Timestamped;
import org.example.expert.domain.manager.entity.Manager;
import org.example.expert.domain.user.entity.User;
import org.hibernate.annotations.BatchSize;
import java.util.ArrayList;
import java.util.List;
@Getter
@Entity
@NoArgsConstructor
@Table(name = "todos")
public class Todo extends Timestamped {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String contents;
private String weather;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@BatchSize(size = 10)
@OneToMany(mappedBy = "todo", cascade = CascadeType.REMOVE)
private List<Comment> comments = new ArrayList<>();
@BatchSize(size = 5)
@OneToMany(mappedBy = "todo", cascade = CascadeType.PERSIST)
private List<Manager> managers = new ArrayList<>();
public Todo(String title, String contents, String weather, User user) {
this.title = title;
this.contents = contents;
this.weather = weather;
this.user = user;
this.managers.add(new Manager(user, this));
}
}
'트러블 슈팅' 카테고리의 다른 글
| 기간 검색에서 시작일 또는 종료일이 없을 경우 발생한 문제 개선 (0) | 2024.10.11 |
|---|---|
| QueryDsl에서 List<Dto> 방식과 List<Entiry> 방식 (0) | 2024.10.11 |
| @AuthenticationPrincipal AuthUser authUser 에서 NullPointerException 발생 문제 (0) | 2024.10.11 |
| 테이블 이름이 예약어와 같은 경우의 에러 ( 테이블 이름 order ) (0) | 2024.09.21 |
| [깃 파일 권한 문제] warning: unable to access … Permission denied (1) | 2024.09.21 |