김영한의 ORM 표준 JPA 프로그래밍(기본편) - 연관관계 단방향 맵핑, 양방향 맵핑

2025. 2. 5. 21:19·김영한의 ORM 표준 JPA 프로그래밍(기본편)

객체지향적으로 외래키 맵핑 방법

@Entity
public class Member {
	@Id @GeneratedValue
	private Long id;

	@Column(name = "USERNAME")
	private String name;
	private int age;

// @Column(name = "TEAM_ID")
// private Long teamId;

	@ManyToOne
	@JoinColumn(name = "TEAM_ID")
	private Team team;
	…
  • 위 코드에서 주석친 것 처럼 외래키를 사용하면 객체지향적이지 못함
  • 객체지향적으로 외래키를 맵핑하려면 해당 객체에 @ManyToOne과 같은 어노테이션을 설정
  • @ManyToOne은 다대일 관계로 해당 어노테이션을 선언한 클래스가 "다"가 됨
  • 즉, 멤버가 "다"고 팀이 "일"이 됨.
  • 또한, 대상 클래스에서 어떤 키에 맵핑될지를 정의해야 해서 @JoinColumn으로 해당 필드 값을 선언

 

연관관계 저장, 조회, 수정 방법

//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);

//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team); //단방향 연관관계 설정, 참조 저장
em.persist(member);

//조회
Member findMember = em.find(Member.class, member.getId());
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();


// 새로운 팀B
Team teamB = new Team();
teamB.setName("TeamB");
em.persist(teamB);
// 회원1에 새로운 팀B 설정
member.setTeam(teamB);

 

 

연관관계 양방향 맵핑 방법

@Entity
public class Team {
	@Id @GeneratedValue
	private Long id;
	private String name;

	@OneToMany(mappedBy = "team")
	List<Member> members = new ArrayList<Member>();
 	…
}
  • 이전에 Member에서 단방향 맵핑을 한것과 똑같이, Team에서 단방향 맵핑을 해주면 양방향 맵핑이 됨.
  • 반대로 일대다 관계이므로 @OneToMany를 선언해주면 됨
  • 단, 이때 연관관계의 주인을 정해야 함
    • 연관관계의 주인만이 외래 키를 관리함(등록, 수정)
    • 주인이 아닌쪽은 읽기만 가능
    • 주인은 mappedBy 속성을 사용하지 않음
    • 주인이 아니면 mappedBy속성으로 주인을 지정
    • 주인은 외래키가 있는 곳을 주인으로 정해라(다대일 관계에서 "다"인 것)
  • 연관관계의 주인은 Team이 아니라 Member이므로 Team에서 mappedBy로 Member의 외래키인 "member"를 지정

 

양방향 맵핑시 상대방 값 입력 방법

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

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

//역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
  • 위의 코드는 Team, Member가 서로 양방향 맵핑 관계인데, Team에서만 member를 추가한 상황
  • 하지만, 이전에 설명했듯이 연관관계의 주인만이 외래 키를 관리함
  • 따라서, 값 추가를 주인인 Member가 아닌 Team에서 하면 반영이 되지 않음.
  • 위와 같은 예시는 양방향 맵핑에서 가장 많이 하는 실수
  • 해결 방법: 항상 양쪽에 값을 설정하자
    • 항상 양쪽에 값을 설정하면 값이 입력이 되지 않는 문제를 방지할 수 있음
    • 또한, 영속성 컨텍스트때문에 값 입력이 제대로 되지 않는 문제도 해결할 수 있음

 

연관관계 편의 메서드

...
public void setTeam(Team team){
	this.team = team;
}

public void changeTeam(Team team){
	this.team = team;
	team.getMembers().add(this);
}
  • 양방향 맵핑시 양쪽에 모두 값 설정을 하도록 하기 위해서는 한쪽에서 값 등록을 할 때 상대방 쪽도 등록해주면 됨
  • 위와 같이 changeTeam 메서드에서 Member의 team 필드를 세팅해줄 때 팀의 멤버에도 자신(member)를 넣어줌
  • 이 때, 기존 setTeam은 setter 메서드이기 때문에 setter는 고유의 동작만 하도록 놔두고 changeTeam과 같은 새로운 메서드를 써주는게 좋음
  • 이는 Member에서 해주지 않고 Team에서 해줘도 상관은 없긴 함.

 

양방향 맵핑시 무한 루프 주의

  • 롬복의 toString() 함수가 구현되어 있을 때 Member 객체의 toString() 함수를 부른다면 내부 team을 toString()하게 될 것이고, team은 또 내부의 member의 toString()을 부르고 이게 무한 반복됨
  • 따라서, 양방향 맵핑시에는 lombok의 toString()은 사용되지 않도록 꼭 조심해야함
  • 또한, Controller에서 Response 할 때 Entity로 Response를 하게 되면 자동으로 json으로 변환이 되는데, 이러한 json 변환시에도 Member의 Team이 json화 되면서 Team의 Member가 또 json되고 이러한 문제가 발생할 수 있음.
  • 따라서, 이러한 json 문제를 조심해야하며 Controller에서 Response시에는 Entity가 아닌 DTO를 사용해야 함

 

양방향 맵핑이 필요한가?

  • 양방향 맵핑은 여러가지 문제점들을 가지고 있음.
  • 따라서 왠만하면 단방향 맵핑으로 조회를 해야 함
  • 실제로, 객체의 관계에서나 양방향 맵핑이 있지 DB 테이블에는 서로를 담고 있는 양방향 맵핑 관계는 없음.
  • 즉, 서로를 연관지으로면 단방향 맵핑만으로도 충분하다는 말
  • 따라서, 기본적으로는 단방향 맵핑을 잘 해주고 추후에 정말 필요한 순간에 양방향 맵핑을 그 때 추가해줘도 됨.

'김영한의 ORM 표준 JPA 프로그래밍(기본편)' 카테고리의 다른 글

김영한의 ORM 표준 JPA 프로그래밍(기본편) - 상속관계 맵핑과 - @MappedSuperclass  (1) 2025.02.06
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 다대일, 일대다, 일대일, 다대다  (1) 2025.02.05
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 연관관계맵핑과 Primary Key  (2) 2025.02.05
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 영속성 컨텍스트와 플러시  (2) 2025.02.05
김영한의 ORM 표준 JPA 프로그래밍(기본편) - JPA, Hibernate, JPQL  (4) 2025.02.04
'김영한의 ORM 표준 JPA 프로그래밍(기본편)' 카테고리의 다른 글
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 상속관계 맵핑과 - @MappedSuperclass
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 다대일, 일대다, 일대일, 다대다
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 연관관계맵핑과 Primary Key
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 영속성 컨텍스트와 플러시
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (242)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (118)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      @discriminatorcolumn
      프록시
      페치 조인
      프록시 팩토리
      락
      JPQL
      김영한
      WAS
      Target
      단방향 맵핑
      자바
      typequery
      reentarantlock
      빈 후처리기
      gesingleresult
      @discriminatorvalue
      requset scope
      양방향 맵핑
      조회 성능 최적화
      log trace
      버퍼
      cglib
      Thread
      고급
      jpq
      @within
      스레드
      @args
      jdk 동적 프록시
      hibernate5module
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    김영한의 ORM 표준 JPA 프로그래밍(기본편) - 연관관계 단방향 맵핑, 양방향 맵핑
    상단으로

    티스토리툴바