HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
Spring Data
Spring Data
/
🧣
JPA(Java Persistence API)
/
🎽
Relation
/
⛳
단방향, 양방향 연관관계 사용(등록, 수정, 삭제, 조회)
⛳

단방향, 양방향 연관관계 사용(등록, 수정, 삭제, 조회)

단방향저장조회수정연관관계 제거연관된 엔티티 삭제양방향연관관계 저장양방향 연관관계의 주의점순수한 객체까지 고려한 양방향 연관관계 → 연관관계 편의 메소드 사용연관관계 편의 메서드

단방향

저장

JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 함
Team team1 = new Team("team1", "팀1"); em.persist(team1); Member member1 = new Member("member1", "회원1"); member1.setTeam(team1);// 연관관계 설정 member1 -> team1 em.persist(member1); Member member2 = new Member("member2", "회원2"); member2.setTeam(team1); // 연관관계 설정 member2 -> team1 em.persist(member2);

조회

  • 연관관계가 있는 엔티티를 조회하는 방법
    • 객체 그래프 탐색
    • 객체지향 쿼리 사용(JPQL)

수정

  • dirty Checking을 통해 트랜잭션 커밋되면서 자동 반영

연관관계 제거

Member member1 = em.find(Member.class, "member1"); member1.setTeam(null); // 연관관계 제거 /* UPDATE MEMBER SET TEAM_ID=null, .. WHERE ID = 'member1'; */

연관된 엔티티 삭제

  • 연관된 엔티티를 삭제하려면 기존에 있던 연관관계를 먼저 제거하고 삭제해야 함
  • 그렇지 않으면 외래 키 제약 조건으로 인해 데이터베이스에서 오류가 발생함
member1.setTeam(null); // 회원 1 연관관계 제거 member2.setTeam(null); // 회원 2 연관관계 제거 em.remove(team);

양방향

🪆
@OneToMany 단방향 문제점
1:N N: 1 양방향 매핑
양방향 매핑 시에는 연관관계의 주인을 설정해주어야 하고, mappedBy를 쓰는 엔티티가 연관관계의 주인이 아닌 쪽임. 연관관계의 주인은 외래키를 갖고 있는 테이블
public class Team{ @OneToMany(cascade=ALL, mappedBy = "team") // mappedBy는 필드이름 private List<Member> members = new ArrayList<>(); } public class Member{ @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name="team_id") // db에서 관리할 컬럼이름 private Team team; }
 

연관관계 저장

Team team1 = new Team("team1", "팀1"); em.persist(team1); Member member1 = new Member("member1", "회원1"); member1.setTeam(team1); // 연관관계 설정 member1 -> team1 em.persist(member1); Member member2 = new Member("member2", "회원2"); member2.setTeam(team1); // 연관관계 설정 member2 -> team1 em.persist(member2);
  • 연관관계의 주인인 Member.team 필드를 통해 회원과 팀의 연관관계를 설정하고 저장함
  • 양방향 연관관계는 연관관계의 주인이 외래 키를 관리하여, 주인이 아닌 방향은 값을 설정하지 않아도 데이터베이스에 외래 키 값이 정상 입력됨
    • team1.getMembers().add(member1); // 무시(연관관계의 주인이 아님) team1.getMembers().add(member2);

양방향 연관관계의 주의점

  • 연관관계의 주인에는 값을 입력하지 않고 주인이 아닌 곳에만 값을 입력하면 외래키 값이 정상적으로 저장되지 않음
Member member1 = new Member("member1", "회원1"); em.persist(member1); Team team1 = new Team("team1", "팀1"); team1.getMembers().add(member1); em.persist(team1);
  • 이후 member를 조회하면 TEAM_ID값은 null로 조회됨

순수한 객체까지 고려한 양방향 연관관계 → 연관관계 편의 메소드 사용

  • 위의 방식으로 member.setTeam() 후 persist를 하면 외래키는 잘 들어가지만 객체에서는 양방향 관계가 맺어지지 않으므로 객체까지 고려한다면 양방향으로 관계를 맺어주어야 함
  • 객체 관점에서는 양쪽 방향 모두 값을 입력해주는 것이 가장 안전함
Team team1 = new Team("team1", "팀1"); Member member1 = new Member("member1", "회원1"); Member member2 = new Member("member2", "회원2"); member1.setTeam(team1); // 연관관계 설정 member1 -> team1 member2.setTeam(team1); // 연관관계 설정 member2 -> team1 List<Member> members = team1.getMembers(); System.out.println("members.size = " + members.size()); // 0
Team team1 = new Team("team1", "팀1"); Member member1 = new Member("member1", "회원1"); Member member2 = new Member("member2", "회원2"); member1.setTeam(team1); // 연관관계 설정 member1 -> team1 team1.getMembers().add(member1); // 연관관계 설정 team1 -> member1 member2.setTeam(team1); // 연관관계 설정 member2 -> team1 team1.getMembers().add(member2); // 연관관계 설정 team1 -> member2 List<Member> members = team1.getMembers(); System.out.println("members.size = " + members.size()); // 2

연관관계 편의 메서드

public void setTeam(Team team){ if(this.team != null){ this.team.getMembers().remove(this); } this.team = team; this.getMembers().add(this); } public void addMember(Member member){ this.members.add(member); if(member.getTeam() != this){ // 무한루프에 빠지지 않도록 체크 member.setTeam(this); } }
  • 편의 메소드는 한 곳에만 작성하거나 양쪽 다 작성할 수 있는데, 양쪽 다 작성하면 무한루프에 빠지므로 주의하기