JPA의 n+1 문제를 해소하는 다양한 방식이 있다. 가장 기본적으로는 페치 전략을 lazy로 바꾼다. 그리고 join을 할 때 fetch를 하거나 distinct를 하여 중복을 제거한다. 이런 방식으로 도전을 했는데 실패한 문제가 있었다. 해당 코드는 아래와 같다.
entity Member.java
@ToString
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<book> bookList = new ArrayList<>(); .........(핵심문제)
...후략...
}
MemberRepositoryTest.java
@Autowired
private final MemberRepository repository;
@Test
@Transactional(readOnly = true)
public void test(){
List<Member> members = repository.findAll();......(1)
members.stream().forEach(member->{
System.out.println(member.toString());........(2)
});
}
(1) 에서는 쿼리 한 번이 생성된다.
(2) 에서는 members.size()만큼 List< book> bookList를 출력하는 쿼리가 발생한다. 나는 (2)의 문제가 join 과 유사한 문제라고 생각했다. 그러므로 fetch 전략을 변경하거나 distinct를 변경하고자 했다. 그러나 해소되지 않았다. 여러 시도 끝에 해결했다. 그 해결책은 아래와 같다.
MemberRepositoryTest.java
public void test(){
List<Member> members = repository.findAll();
members.stream().forEach(member->{
System.out.println(member.getName());........(2) 수정
});
}
Member.java
@BatchSize(size = 50)..........(3)
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<Borrow> borrowList = new ArrayList<>();
for (Member member : result) {
System.out.println(member.toString());.......(2) 수정
}