인프런 커뮤니티 질문&답변

Anonymous님의 프로필 이미지

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

orphanRemoval에서 발생하는 쿼리 관련하여 질문드립니다.

해결된 질문

작성

·

138

·

수정됨

0

안녕하세요.

OneToMany 관계에서 orphanRemoval = true 옵션으로 데이터 제거 관련하여 질문드립니다.

 

MemberService.removeAddress() 로직에서 address를 제거하면 select address -> select member -> select address -> delete 순으로 쿼리가 발생합니다.

 

select address 쿼리가 2번 발생하는데, 일반적으로 쿼리 2번을 발생시키면서 고아 객체 제거를 진행하는 걸까요?

 

아니면 다른 방식의 remove 과정이나 또는 select address 쿼리를 1번으로 줄일 수 있는 방법이 있다면 알려주실 수 있을까요?

 

감사합니다.

 

@RequiredArgsConstructor
@Slf4j
@Service
public class MemberService {

  private final AddressRepository addressRepository;

  @Transaction
  public void removeAddress(Long addressId) {
    Address address = addressRepository.findById(addressId)
                                       .orElseThrow(() -> new Exception());
    Member member = address.getMember();
    member.getAddresses().remove(address);
  }

}

 

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    @OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST, orphanRemoval = true)
    private final List<Address> addresses = new ArrayList<>();

    // .. 중략
}

 

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "address_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

    // .. 중략
}

 

답변 2

1

Anonymous님의 프로필 이미지
Anonymous
질문자

제가 생각을 잘못했네요^^;

그냥 바로 deleteById() 로 처리하면 해결되네요.

0

안녕하세요, 인프런 AI 인턴입니다.

질문하신 내용에 대해 orphanRemoval=true 설정 시 발생하는 쿼리의 수와 관련된 고민을 해결할 수 있을 것 같은 기존 답변을 찾았습니다.

“orphanRemoval 동작에 관한 질문 드립니다.”에서는 orphanRemoval 속성이 설정된 상황에서의 동작과 관련된 질문이 있었습니다. 여기서 김영한 지식공유자께서는 orphanRemoval의 의도와 사용 시 주의할 점에 대해 설명해 주셨어요. 다만, 해당 답변은 orphanRemoval의 동작 방식에 대한 일반적인 설명을 포함하고 있고, 질문자님의 구체적인 쿼리 발생 상황에 대한 해결책을 제시하지는 않습니다.

예상되는 발생 구조는 다음과 같습니다:

  1. addressRepository.findById(addressId) 호출 시 첫 번째 select address 쿼리가 실행됩니다.
  2. address.getMember() 호출 시 member 엔티티를 로딩하기 위해 select member 쿼리가 실행됩니다.
  3. 고아 객체(여기서는 address) 제거 로직 실행 시 또 다시 해당 객체를 확인하기 위해 select address 쿼리가 발생할 수 있습니다.
  4. 실제로 address를 제거하는 delete 쿼리가 실행됩니다.

이와 같은 상황에서 보다 효율적으로 데이터를 처리하기 위한 방안을 모색하는 것이 중요합니다. 하지만, 현재 공급된 정보 내에서 쿼리 발생 횟수를 줄이는 구체적인 방안에 대한 직접적인 해결책을 찾지 못하였습니다. 또한, JPA의 동작 방식상 orphanRemoval=true로 설정했을 때 발생하는 쿼리의 수는 JPA 구현체의 최적화 정책에 따라 달라질 수 있어, 일반적인 상황에서는 개발자가 쿼리 발생 수를 직접 최적화하기 어려울 수 있습니다.

추가적인 최적화를 고려하시려면, orphanRemoval 의 사용 대신 직접적인 삭제 쿼리(JPQL, Querydsl 등)를 구성하여 사용하는 방법을 검토하실 수 있습니다. 이와 관련하여 더 효과적인 접근법을 고민하시고 싶다면, 구체적인 케이스와 함께 새로운 질문을 등록해 주시는 것도 좋은 방법입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.