public class Code {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long codeId;
private String codename;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "upper_code_id")
@JsonIgnore
private Code parentCode;
@OneToMany(mappedBy = "parentCode", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Code> childCodes;
public CodeDTO toDTO() {
Set<Long> convertedCodes = new HashSet<>();
if (convertedCodes.contains(codeId)) {
return null;
}
CodeDTO.CodeDTOBuilder builder = CodeDTO.builder();
builder.codeId(codeId)
.codename(codename);
if(parentCode != null) {
CodeDTO parentCodeDTO = parentCode.toDTO();
builder.parentCodeDTO(parentCodeDTO);
}
if (childCodes != null && !childCodes.isEmpty()) {
List<CodeDTO> childCodeDTOs = childCodes.stream()
.map(Code::toDTO)
.filter(Objects::nonNull)
.collect(Collectors.toList());
builder.childCodesDTO(childCodeDTOs);
}
return builder.build();
}
}
Hibernate: select c1_0.code_id,c1_0.codename,c1_0.upper_code_id from code c1_0 where c1_0.codename=?
Hibernate: select c1_0.code_id,c1_0.codename,c1_0.upper_code_id from code c1_0 where c1_0.code_id=?
Hibernate: select c1_0.upper_code_id,c1_0.code_id,c1_0.codename from code c1_0 where c1_0.upper_code_id=?
이렇게 무한루프를 해결하고 나서 부모 + 자식을 가지고오는 과정에서 n+1쿼리문이 생기는 문제가 발생했다.
이는 양방향 참조관계를 설정할 때 해놓은 FetchType.LAZY때문으로, 자식이 필요할 때 쿼리를 발생시키는 방식이기 때문에 N+1참조 관계가 발생한다.
하지만 그렇다고 해서 한번에 모든 객체를 다 가지고 오면 속도 저하가 생길 수도 있으므로 EAGER로 할 수도 없는 노릇이었다.
결국은 부모 + 자식을 한번에 조인해서 가지고 오는 쿼리문을 작성해야했고, 다음과 같은 쿼리문으로 수정했다.
@Query("SELECT c FROM Code c " +
"LEFT JOIN FETCH c.parentCode " +
"LEFT JOIN FETCH c.childCodes " +
"WHERE c.codename = :codename")
public Code findByCodename(String codename);
User
Hibernate: select c1_0.code_id,c2_0.upper_code_id,c2_0.code_id,c2_0.codename,c1_0.codename,p1_0.code_id,p1_0.codename,p1_0.upper_code_id from code c1_0 left join code p1_0 on p1_0.code_id=c1_0.upper_code_id left join code c2_0 on c1_0.code_id=c2_0.upper_code_id where c1_0.codename=?
Hibernate: select c1_0.upper_code_id,c1_0.code_id,c1_0.codename from code c1_0 where c1_0.upper_code_id=?
Hibernate: select c1_0.upper_code_id,c1_0.code_id,c1_0.codename from code c1_0 where c1_0.upper_code_id=?
Hibernate: select c1_0.upper_code_id,c1_0.code_id,c1_0.codename from code c1_0 where c1_0.upper_code_id
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
default_batch_fetch_size: 1000
Hibernate: select c1_0.code_id,c2_0.upper_code_id,c2_0.code_id,c2_0.codename,c1_0.codename,p1_0.code_id,p1_0.codename,p1_0.upper_code_id from code c1_0 left join code p1_0 on p1_0.code_id=c1_0.upper_code_id left join code c2_0 on c1_0.code_id=c2_0.upper_code_id where c1_0.codename=?
Hibernate: select c1_0.upper_code_id,c1_0.code_id,c1_0.codename from code c1_0 where c1_0.upper_code_id in (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?.....