프로젝트를 진행하다가 OneToOne 관계에서 FetchType.LAZY를 설정해주었음에도 즉시 로딩이 실행되 N+1 문제가 발생하는것을 확인했다.
문제의 Entity들
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Table(name = "review")
@Entity
@Builder
public class Review extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long reviewSeq;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "hospital_seq")
private Hospital hospital;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "review")
private Appointment appointment;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_seq")
private Member member;
@Column(nullable = false)
private int starRating;
@Column(nullable = false)
private String content;
}
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicInsert
@Getter
@Table(name = "appointment")
@Entity
@Builder
public class Appointment extends BaseEntity {
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Id
private Long appointmentSeq;
@JoinColumn(name = "member_seq")
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
@JoinColumn(name = "children_seq")
@ManyToOne(fetch = FetchType.LAZY)
private Children children;
@JoinColumn(name = "doctor_seq")
@ManyToOne(fetch = FetchType.LAZY)
private Doctor doctor;
@JoinColumn(name = "hospital_seq")
@ManyToOne(fetch = FetchType.LAZY)
private Hospital hospital;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "review_seq")
private Review review;
@Column(nullable = false)
private LocalDateTime appointmentDate;
@Column(nullable = false)
private String appointmentHour;
@Column(nullable = false)
private String appointmentMinute;
@ColumnDefault("'0'")
private String status;
@Column
private String note;
}
문제의 Entity들의 관계를 살펴보면 Appointment가 연관관계의 주인인것을 확인할 수 있다.
여기서 fetch join을 사용해 조건에 맞는 entity를 조회해주는 Repository를 작성해주자
@Repository
public interface ReviewRepository extends JpaRepository<Review, Long> {
@Query("select r from Review r"
+ " join fetch r.member m"
+ " join fetch r.hospital h"
+ " where r.hospital.hospitalSeq = :hospitalSeq"
)
Page<Review> findAllWithMember(Pageable pageConfig, @Param("hospitalSeq") Long hospitalSeq);
}
Review와 Member, Hospital Entity까지 조회해오는 쿼리를 작성했다.
작성된 쿼리와 엔티티의 세팅값을 보면 Review와 Member, Hospital을 조회하는 쿼리만 나가야 정상이다.
하지만 작동된 쿼리를 살펴보면 호출하지 않은 Appointment까지 조회가 되는것을 볼 수 있다.
N+1 문제가 발생해버린것이다.
이를 해결하는 방법은 아주 간단하다.
단지 연관관관계의 주인을 바꿔주는 방법으로 해결이 가능하다.
이유는 해당 블로그를 참고하여 이해했다.
JPA - OneToOne관계 N+1문제
안녕하세요. 오늘은 JPA 작업을 하시면서 발생하는 양방향 OneToOne 관계에서 주인과 주인이아닌 LazyLoding(지연로딩)으로 설정 했지만 적용이 안되고 eagerLoding(즉시로딩)으로 조회해서 발생하는 흔
pooney.tistory.com
Enrity의 ID값을 직접 컬럼에 저장해줘 n+1 문제를 해결했다!
https://coding-camel.tistory.com/140
'코딩딩 > Error' 카테고리의 다른 글
Spring Data JPA 사용시 Repository BeanCreationException (0) | 2024.01.09 |
---|---|
파이썬 셀레니움 웹 스크레핑 시 hidden에 숨겨져있는 src 경로 가져오기 (3) | 2024.01.08 |
OneToOne 양방향 관계 지연로딩 안먹히는 문제 해결법 (0) | 2024.01.05 |
Builder 패턴 사용시 ArrayList가 초기화 되지 않는 문제 (1) | 2024.01.03 |
Null값이 들어올 수 없는 @PathVariable에도 Wrapper class를 사용해야 할까? (1) | 2023.12.28 |