강의

멘토링

로드맵

Inflearn brand logo image

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

조희제님의 프로필 이미지
조희제

작성한 질문수

실전! 스프링 데이터 JPA

영속성 전이와 연관관계

작성

·

83

·

수정됨

0

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]

안녕하세요 선생님 강의를 통해 배움을 얻고 프로젝트를 하며 성장 하고 있습니다.

프로젝트를 하던중 영속성 전이와 관련하여 궁금한점이 생겨 질문 드립니다.

( 영한님 JPA 강의에 질문 하는것이 맞으나 JPA는 책을 사서 여기에 질문 드립니다 ㅠㅠ )

 

회원과 주소는 양방향 관계를 두고 있습니다.

회원과 주소를 연관관계 매핑하여 회원을 저장하면 영속성 전이를 통해

주소가 같이 저장 됩니다.

 

그런데 문제는 둘다 영속 상태일때 주소를 제거 하면 delete 쿼리가 나가지 않았습니다.

이런 저런 실험을 해본 결과 영속성 전이 때문에 삭제 되지 않은것으로 보았습니다.

영속 대상인 주소를 삭제 하려고 했으나 회원의 연관관계인 Address는 그대로 있기 때문에

영속성 전이로 인해 삭제가 되지 않았다로 판단 하였습니다.

 

영속성 컨텍스트에 주소만 있을 경우 주석 으로된 부분을 실행하면

영속성 전이를 수행할 회원이 없기 때문에 delete 쿼리가 나가게 됩니다.

제가 생각한게 맞는지 궁금하여 질문 드립니다.

 

밑의 예시의 경우 회원이 영속 상태인 경우

영속성 전이 때문에 연관관계를 끊지 않으면 영속 대상인 주소가 delete가 안되는게 맞을까요?

 

@DisplayName("회원과 연관된 주소를 제거할때 자식인 주소를 제거 하면 delete 쿼리가 발생하지 않는다.")
@Test
void deleteAddress() {
    //given
    User user = new User("회원");
    Address address = new Address("주소");
    address.connectUser(user);

    //when
    em.persist(user);
    em.flush();

    boolean isAddressManaged = em.contains(address);
    System.out.println("Address is managed? " + isAddressManaged);

    addressRepository.deleteById(address.getId());
    em.flush(); em.clear();

        //then
//Address findAddress = addressRepository.findById(address.getId()).orElseThrow()                           //addressRepository.deleteById(findAddress.getId());
//em.flush();
}
image.png

 

[ 회원 ]

@Getter @Setter
@Table(name = "users")
@Entity
public class User {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(mappedBy = "user", cascade = CascadeType.PERSIST)
    private Address address;

    protected User() {}

    private String name; 

    public void connectAddress(Address address){
        this.address = address;
    }

}
@Getter
@Entity
public class Address {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    private String addressName;

    protected Address() {}

    public Address(String addressName) {
        this.addressName = addressName;
    }

    public void connectUser(User user){
        this.user = user;
        user.connectAddress(this);
    }
}

 

 

답변 2

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 조희제님

다음 링크를 참고해주세요 🙂

https://inf.run/fcoyT

감사합니다.

조희제님의 프로필 이미지
조희제
질문자

감사합니다!

0

안녕하세요, 인프런 AI 인턴입니다. 조희제님께서 주신 질문에 대한 것을 살펴보도록 하겠습니다.

프로젝트를 진행하면서 JPA의 영속성 전이에 관련된 문제를 겪고 계신 것 같습니다. 여기서 핵심은 “영속 컨텍스트에 있지 않다면 연관관계를 통해 영속성 전이가 이루어지지 않는가?” 하는 것인데요. 다음을 참고해 보시면 이해가 좀 더 쉬울 것 같습니다.

  1. 영속성 전이와 연관관계: 영속성 전이는 부모 엔티티의 상태를 자식에게 전이시키는 기능입니다. 이는 영속 상태의 부모 엔티티가 자식 엔티티를 persist, merge, remove한 경우 관련된 자식 엔티티에도 해당 작업이 전이되는 것을 의미합니다.

  2. 영속성 전이와 삭제: 영속성 전이는 CascadeType.REMOVE 설정이 되어 있는 경우, 부모 엔티티가 삭제되면 자식 엔티티도 같이 삭제될 수 있습니다. 그러나, 부모 엔티티(User)가 삭제되지 않는 한, 자식(Address)을 직접 delete하는 경우 부모로부터 영속성 전이에 의해 보호되지 않는다면 delete 쿼리가 발생하지 않을 수 있습니다.

  3. 연관관계 유지: 주어진 코드는 실제로 Address를 삭제하기 위해 repository를 사용하고 있지만, 부모 User의 연관관계가 여전히 Address를 가리키고 있기 때문에 JPA는 이 시점에서 Address를 삭제하지 않는 것으로 보입니다. delete 쿼리가 발생하지 않는 이유는 Address가 User와의 연관성을 통해 영속성 전이의 영향을 받고 있기 때문입니다.

따라서, 자식 엔티티(Address)를 성공적으로 삭제하기 위해서는:
- User 엔티티와 Address의 연결(연관관계)을 끊어주어야 합니다. 이는 user.setAddress(null);처럼 구현할 수 있습니다.

다음 링크들은 영속성 전이 및 관계와 관련된 다른 Q&A들입니다. 비슷한 상황을 다뤘기 때문에 더 깊이 있는 이해에 도움이 될 수 있습니다:
- 영속성 전이+고아 객체 질문
- 영속성 전이 질문
- remove() 동작 방식 관련 질문

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

조희제님의 프로필 이미지
조희제
질문자

궁금한점이 영속성 전이 주체와 대상이 둘다 영속 상태일때

대상이 삭제 안되는 이유가 궁금해서 질문을 드린거라 답변을 주시면 감사합니다

주석을 해제 하여 수행 하면 주소가 삭제되지만 위 예시는 주소가 삭제 되지 않습니다.

image.png

 

@DisplayName("회원과 연관된 주소를 제거할때 자식인 주소를 제거 하면 delete 쿼리가 발생하지 않는다.")
@Test
void deleteAddress() {
    //given
    User user = new User("회원");
    Address address = new Address("주소");
    address.connectUser(user);

    //when
    em.persist(user);
    em.flush();

    boolean isAddressManaged = em.contains(address);
    System.out.println("Address is managed? " + isAddressManaged);

    addressRepository.deleteById(address.getId());
    em.flush(); em.clear();

    //then
    Address findAddress = addressRepository.findById(address.getId()).orElseThrow();
    addressRepository.deleteById(findAddress.getId());
    em.flush();
}
조희제님의 프로필 이미지
조희제

작성한 질문수

질문하기