다대일[N:1]
- JPA에서 가장 많이 사용하고, 꼭 알아야 하는 다중성이다.
- DB설계상 일대다에서 '다' 쪽에 외래키가 존재해야한다.
다대일 단방향 매핑
- JPA의 @ManyToOne 어노테이션을 사용해서 다대일 관계를 매핑
- @JoinColumn은 외래키를 매핑할 때 사용한다. name은 매핑할 외래 키의 이름.
public class Member{
...
@ManyToOne
@JoinCoulmn(name="TEAM_ID")
private Team team;
}
다대일 양방향 매핑
- 반대쪽에서 일대다 단방향 매핑을 해주면 된다.(객체기준으로, 컬렉션을 추가하자)
- 반대에서 단방향 매핑을 한다고 해서 DB테이블에 영향을 전혀 주지 않는다.
- 다대일의 관계에서 다 쪽에서 이미 연관관계 주인이 되어서 외래키를 관리하고 있다.
- 반대쪽에서 일대다 단방향 매핑. JPA의 @OneToMany 어노테이션을 사용한다.
- 어디에 매핑 되었는지에 대한 정보를 표시하는 (mappedBy="team") 을 꼭 넣어줘야 한다.
- (mappedBy = "team") 에서 team은 Member에서 외래키로 매핑된 필드명
public class Team {
...
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
...
}
일대다[1:N]
- 일대다 관계에서는 일이 연관관계의 주인이다.
- 일 쪽에서 외래키를 관리하겠다는 의미가 된다
- 결론 먼저 말하자면, 표준스펙에서 지원은 하지만 실무에서는 사용을 권장하지 않는다.
일대다 단방향 매핑
- 팀과 멤버가 일대다 관계이다.
- Team이 Members(컬렉션)을 가지는데, Member의 입장에서는 Team을 참조하지 않아도 된다는 설계이다.
- 그러나 DB 테이블 입장에서 보면 무조건 일대다에서 '다' 쪽에 외래키가 들어간다.
- Team에서 members가 바뀌면, DB의 member 테이블에서 업데이트 쿼리가 나가는 상황이 발생한다.
JPA의 @OneToMany와 @JoinColumn()을 이용해 일대다 단방향 매핑을 설정할 수 있다.
Member member = new Member();
member.setUsername("MemberA");
em.persist(member);
System.out.println("-----멤버 저장");
Team team = new Team();
team.setName("TeamA");
team.getMembers().add(member);
em.persist(team);
System.out.println("-----팀 저장");
tx.commit();
이렇게 실행하면 쿼리에서 트랜잭션 커밋 시점에 create one-to-many row로 시작되는 주석과 함께 Member 테이블을 업데이트 하는 쿼리가 나간다.
★일대다 단방향의 정리
- 일대다 단방향은 일대다의 일이 연관관계 주인이다.
- 테이블 일대다 관계는 항상 다(N)쪽에 외래키가 있다.
- 객체와 테이블의 패러다임 차이 때문에 객체의 반대편 테이블의 외래키를 관리하는 특이한 구조다.
- @JoinColumn을 반드시 사용해야 한다. 그렇지 않으면 조인 테이블 방식을 사용한다.
★일대다 단방향 매핑의 문제점과 해결방안
- 일단 업데이트 쿼리가 나간다. 성능상 좋지 않으나 크게 문제되지는 않는다.
- 위 예시로 살펴보면, Team의 엔티티를 수정했는데 Member의 엔티티가 업데이트되는 상황이 발생한다.
- 테이블이 적을때는 크게 문제가 되지 않지만 실무에서는 테이블이 수십개가 엮어서 돌아간다.
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자
일대다 양방향 매핑
- 이런 매핑은 공식적으로 존재X
- @JoinColumn(insertable=false, updatable=false)
- 읽기 전용 필드를 사용해서 양방향 처럼 사용하는 방법
- 다대일 양방향을 사용하자
일대일[1:1]
- 일대일 관계는 그 반대도 일대일이다.
- 일대일 관계는 특이하게 주 테이블이나 대상 테이블 중에 외래 키를 넣을 테이블을 선택 가능하다.
- 주 테이블에 외래키 저장
- 대상 테이블에 외래 키 저장
- 외래키에 데이터베이스 유니크 제약조건이 추가되어야 일대일 관계가 가능하다.
일대일 - 주 테이블에 외래키 단방향
- 회원이 딱 하나의 락커를 가지고 있는 상황이다. 반대로 락커도 회원 한명만 할당 받을 수 있다. 이때, 둘의 관계는 일대일 관계이다.
- 이 경우 멤버를 주 테이블로 보고 주 테이블 또는 대상 테이블에 외래키를 지정할 수 있다.
- 다대일[N:1] 단방향 관계와 JPA 어노테이션만 달라지고 거의 유사하다.
일대일- 주 테이블에 외래키 양방향
- 다대일[N:1] 양방향 매핑처럼 외래키가 있는곳이 연관관계의 주인이다.
- JPA @OneToOne 어노테이션으로 일대일 단방향 관계를 매핑하고, @JoinColumn을 넣어준다.
- 반대편에 mappedBy를 적용시켜주면 일대일 양방향 관계 매핑이 된다.
- 마찬가지로, mappedBy는 읽기 전용으로 참조만 가능하다.
일대일 - 대상 테이블에 외래키 단방향
일대일 관계에서 대상 테이블에 외래키를 단방향으로 저장하는 방식은 지원하지 않는다.
일대일 - 대상 테이블에 외래키 양방향
- 일대일 주 테이블에 외래 키 양방향 매핑을 반대로 뒤집었다고 생각하면 된다. 매핑 방법은 같다.
- 주 테이블은 멤버 테이블이지만, 외래 키를 대상 테이블에서 관리하고 주 테이블의 락커 필드는 읽기 전용이 된다.
일대일 정리
• 주 테이블에 외래 키
• 주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
• 객체지향 개발자 선호
• JPA 매핑 편리
• 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
• 단점: 값이 없으면 외래 키에 null 허용
• 대상 테이블에 외래 키
• 대상 테이블에 외래 키가 존재
• 전통적인 데이터베이스 개발자 선호
• 일대일 - 대상 테이블에 외래 키 단방향 매핑을 JPA에서 지원하지 않으므로, 단방향 매핑만 해서는 멤버 객체를 업데이트 했을 때 락커 테이블에 FK를 업데이트 할 방법이 없다. 따라서 양방향 매핑을 해야 한다.
• 장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
• 단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨(프록시는 뒤에서 설명)
다대다[N:N]
- 다대다 매핑의 한계는 테이블에 매핑 정보만 들어가고 이 외의 추가 정보를 넣을 수 없다는 점과 중간 테이블이 숨겨져 있기 때문에 생각하지 못한 쿼리가 나간다는 점이다.
- 다대다는 실무에서 사용하지 말아야 한다.
- 다대다 (@ManyToMany)는 각각 일대다, 다대일 관계로 풀어서 사용하자.
- 연결 테이블용 엔티티를 추가한다. 연결 테이블을 엔티티로 승격시킨다.
- JPA가 만들어준 숨겨진 매핑테이블의 존재를 바깥으로 꺼낸다고 생각하자.
참고