Search
Duplicate

[Spring JPA] 다양한 연관관계 맵핑

날짜
2022/04/29 05:19
상태
스프링 JPA 기본
속성 1
Spring
JAVA
JPA
담당자

연관관계 매핑 시 고려사항 3가지

다중성
단방향, 양방향
연관관계의 주인

다중성

다대일: @ManyToOne
일대다: @OneToMany
일대일: @OneToOne
다대다: @ManyToMany
다중성 같은 경우 간혹 헷갈릴 경우가 발생한다. 그럴 때는 반대쪽으로 생각해보면 된다. 회원과 팀이면 반대로 팀과 회원의 관계를 생각해보면 된다. 일대일의 반대는 일대일, 일대다의 반대는 다대일, 다대다의 반대는 다대다로 대칭 성이 있기 때문이다.
하지만 무엇보다도 중요한건 실무에서는 다대다를 쓰면 안 된다.

단방향, 양방향

테이블
외래 키 하나로 양쪽 조인 가능
사실 방향이라는 개념이 없음
객체
참조용 필드가 있는 쪽으로만 참조 가능
한쪽만 참조하면 단방향
양쪽이 서로 참조하면 양방향

연관관계 주인

테이블은 외래 키 하나로 두 테이블이 연관관계를 맺음
객체 양방향 관계는 A > B, B > A처럼 참조가 2군데
객체 양방향 관계는 참조가 2군데 있음. 둘 중 테이블의 외래 키를 관리할 곳을 지정해야 함
영관 관계의 주인: 외래 키를 관리하는 참조
주인의 반대편: 외래 키에 영향을 주지 않음, 단순 조회만 가능

다대일[N:1]

1) 단방향
DB입창에서 보면 회원이 N, 팀이 1이며 외래 키는 N에 가야 한다. 멤버를 두 명을 넣어도 team_id에 같은 팀을 넣어 줄 수 있다.
정리
가장 많이 사용하는 연관관계
다대일의 반대는 일대다

다대일[N:1]

2) 양방향
양방향으로 설정하는 것이 테이블에 영향을 주는 것은 아니다. 어차피 연관 관계 주인이 외래 키를 관리하기 때문에 객체에서 추가만 해주면 된다.
정리
외래 키가 있는 쪽이 연관관계의 주인
양쪽을 서로 참조하도록 개발

일대다 [1:N]

1) 단방향
이 모델은 권장하지 않는다. 표준 스펙에서 지원하기 때문에 설명. 실무에서는 이 모델은 거의 가져가지 않는다.
팀을 중심으로 관리를 전부 하겠다.
DB입장을 생각해보자. 팀이랑 멤버인데, 무조건 N 쪽에 외래 키를 들어갈 수밖에 없다.Team의 Members 값을 변경했을 때, Member의 Team_id의 값을 업데이트 쳐줘야 된다.
public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");// 애플리케이션 에서 한개만 만들어 져야된다. EntityManager em = emf.createEntityManager();//하나의 단위를 만들때마다 만들어 줘야된다. EntityTransaction tx = em.getTransaction(); tx.begin(); try { Member member = new Member(); member.setName("member1"); em.persist(member); Team team = new Team(); team.setName("teamA"); //외래키가 변경 되어야한다.//외래키는 멤버 테이블에 있다. 결국에 멤버가 업데이트 되야된다. team.getMembers().add(member); em.persist(team);
Java
복사
@Entity public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany @JoinColumn(name = "TEAM_ID") private List<Member> members = new ArrayList<>();
Kotlin
복사
정리
일대다 단방향은 일대다(1:N)에서 일(1)이 연관관계의 주인
테이블 일대다 관계는 항상 다(N) 쪽에 외래 키가 있음
객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조
@JoinColumn을 꼭 사요 해야 함. 그렇지 않으면 조인 테이블 방식을 사용함(중간에 테이블을 하나 추가함)
단점
일대다 단방향 매핑의 단점
엔티티가 관리하는 외래 키가 다른 테이블에 있음
연관관계 관리를 위해 추가로 UPDATE SQL 실행
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자.

일대다 [1:N]

2) 양방향
위와 같이 일대다 양방향 관계과 되면 Team의 Mebers도 Member의 Team도 연관관계의 주인이 되어버려서 망하게 돼버린다. 때문에 Member의 Team을 insertable과 updatable을 false로 넣어서 읽기 전용으로 강제하는 것이다.
정리
이런 매핑은 공식 적으로 존재하지 않는다.
@JoinColumn(insertalbe=false, updatable=false)
읽기 전용 필드를 사용해서 양방향처럼 사용하는 방법
다대일 양방향을 사용하자.

일대일 [1:1]

일대일 관계는 그 반대도 일대일
주 테이블이나 대상 테이블 주에 외래 키 선택 가능
주 테이블에 외래 키
대상 테이블에 외래 키
외래 키에 데이터베이스 유니크(UNI) 제약조건 추가
다대일 양방향 매핑가 비슷하다.
@Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String name; @ManyToOne @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false) private Team team; @OneToOne @JoinColumn(name = "LCOKER_ID") private Locker locker;
Java
복사
@Entity public class Locker { @Id @GeneratedValue private Long id; @OneToOne(mappedBy = "locker") private Member member; private String name; }
Java
복사
연관관계의 주인은 외래 키가 있는 곳
반대편은 mappedBy 적용
정리
주 테이블에 외래 키(주로 액세스 하는 테이블)
주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
객체지향 개발자 선호
JPA 맵핑 편리
장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
단점 : 값이 없으면 외래 키에 null 허용
대상 테이블에 외래 키
대상 테이블에 외래 키가 존재
전통적인 테이버 테이스 개발자 선호
장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
단점 : 프락시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨(프락시는 뒤에서 설명)
이 글은 인프런의
제목 : 자바 ORM 표준 JPA 프로그래밍 - 기본 편
강사 : 김영한 님의 동영상을 참조해 만들었습니다.