본문 바로가기
Framework/🍃Spring

JPA - 양방향 연관관계와 연관관계 주인 - 2

by 발개발자 2022. 12. 15.
반응형

양방향 매핑시에 주의해야할 사항에 대해 알아보자.

 

  연관관계의 주인에 값 미입력

먼저, 양방향 매핑시 가장 많이 하는 실수 중 하나는 연관관계의 주인에 값을 입력하지 않는 것이다.

바로 예시를 봐보자.

Team team = new Team();
team.setName("TeaA");
em.persist(team);

Member member = new Member();
member.setName("member1");

// 역방향 (주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);

em.persist(member);

 

위와 같이 작성할 경우 연관관계의 주인인 Member에서는 Team을 참조하지 못하게 된다. 

왜냐하면, 이전 내용에서 기술했듯이 연관관계의 주인만이 Fk를 핸들링할 수 있기 때문이다.

 

 

 

그렇다면, 연관관계의 주인에만 값을 저장하면 될까?

사실, 객체관점에서 바라보면 순수한 객체관계를 고려하면 항상 양쪽 모두에 값을 입력해야 한다.

JPA를 사용하지 않았을 경우에 양방향매핑 상태인 Team객체의 members와 Member객체의 Team을 꺼내어 사용할텐데, 한쪽에만 값을 입력해주면 반대편에서 값을 꺼내어 쓸 때 반영이 안되어 있기때문이다.

그래서 아래와 같이 양쪽에 값을 다 설정해준다.

Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("member1");

team.getMembers().add(member);
// 연관관계의 주인에 값 설정
member.setTeat(team);

em.persist(member);

 

그렇다면 양방향관계에서는 이렇게 일일이 다 값을 set해주면 너무 번거로울 수 있다.

그래서 이를 도와주기 위해 연관관계 편의 메서드를 생성한다.

 

  연관관계 편의 메서드

연관관계 편의 메서드는 양방향 연관관계에서 서로의 엔티티 값을 넣어줘야 할때, set메서드에서 자동으로 값을 설정하도록 도와주는 방식이다.

아래의 코드와 같이 연관관계의 주인에서 반대편 Entity값을 Set해줄 때 반대편 Entity에도 연관관계의 주인을 Set해주는 구조다.

@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;

// Getter .. 
// Setter ..

public set setTeam(Team team){
    this.team = team;
    team.getMembers().add(this);
}

 이를 통해, 연관관계 주인에서만 객체의 Set을 통해 양쪽 객체의 값 Setting이 완료된다. 

여기서 Member가 참조하는 Team객체가 변경될 경우, 변경되기 전 Team객체가 가지고 있던 Member를 지워서 연관관계를 끊어 줘야한다.

 

 

  양방향 매핑으로 인한 무한루프

양방향 매핑을 할 경우, toString, JSON 생성 라이브러리 등 값을 출력하는 작업을 할 경우 무한루프가 발생할 수 있다.

예시를 직접 봐보자.

 

Member와 Team 객체에 @ToString 어노테이션을 추가하고 아래와 같은 테스트 코드를 돌려보자.

@SpringBootTest
class MemberRepositoryTest {

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private TeamRepository teamRepository;

    @Test
    void 테스트(){
        Member member = new Member();
        Team team = new Team();
        teamRepository.save(team);

        member.setTeam(team);

        memberRepository.save(member);
        team.addMember(member);

        System.out.println("!!!!!!!!!!");
        System.out.println(team);


    }
}

 위와 같이 테스트 코드를 작성할 경우, SOF가 발생하게 된다.

 

ToString으로 서로 계속 순환참조를 하기 때문에 SOF가 발생하게 되는 것이다.

 

 

본 내용은 아래의 강의를 참고했습니다.

https://www.inflearn.com/course/ORM-JPA-Basic

반응형

댓글