다양한 연관관계 매핑!
연관관계 매핑시 고려사항 3가지
- 다중성 (1:n , n:1 ....)
- 단방향, 양방향
- 연관관계의 주인
1) 다중성
다대일 @ManyToOne 제일 많이 씀
일대다 @OneToMany 자주 씀
일대일 @OneToOne 가끔 씀
XX다대다 @ManyToMany 실무에서 쓰면 안 됩니다
다중성 애매할 때?
어떻게 알 수 있지?
- 반대로 생각해보자
회원과 팀의 관계 / 팀과 회원의 관계
n : 1 / 1 : n
2) 단방향, 양방향
테이블은?
외래 키 하나로 두 테이블이 연관관계
사실 방향이라는 개념 XX다대다
객체는?
참조용 필드가 있는 쪽으로만 참조 가능함
한쪽만 참조하면 단방향
양쪽이 서로 참조하면 양방향 ->
객체 입장에서는 방향이 하나입니당! 서로 왔다갔다 하는 것뿐
양방향 관계의 객체는 참조가 두군데임
그 둘 중 참조에서 외래 키를 관리할 곳을 지정해야 합니다
3) 연관관계의 주인
연관관계의 주인 : 외래 키를 관리하는 참조
주인의 반대편 : 외래 키에 영향 못줌, 조회만 가능
@ManyToOne
다대일(n:1)
Member와 Team이 있을 때, 멤버가 N
N쪽에 외래키(FK)가 가야합니다
외래키를 가진 쪽(주인)이
안 가진 쪽 객체를 가져와서 참조하기!
가장 많이 사용하는 연관관계!
단방향 다대일
Member가 주인
@ManyToOne // Member가 n, Team이 1
@JoinColumn(name = "TEAM_ID") // 얘랑 JOIN 할거얌
private Team team;
양방향 다대일
일(Team)에서 다(주인 Member)을 참고할때
@OneToMany (mappedBy = "team") // Member 클래스의 team(변수명) 필드와 연관되어 있어요
private List<Member> members = new ArrayList<>();
다대일 양방향은?
* 외래 키가 있는 쪽이 연관관계의 주인이다
* 양쪽을 서로 참조하도록 개발한다!
@OneToMany
일대다(1:n)
DB에서는 다(n) 쪽에 무조건 외래키가 들어간다
일대다 단방향 (실무에서 거의 안 씁니다요~!)
일(1)이 주인
@OneToMany // team이 주인
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
// 1 Insert
Member member = new Member();
member.setUsername("mamber1");
em.persist(member);
Team team = new Team();
team.setName("teamA");
// 얘가 한번 더 업데이트 되어야함
// 3 Update
team.getMembers().add(member);
// 2 Insert
em.persist(team);
우리는 persist만 두번 실행했지만,
쿼리는 세번
insert , insert , update 실행된다
왜?
외래키가 없는 입장에서는 insert가 먼저 되어도 외래키가 존재하지 않아서
일단 insert를 하고, 외래키 테이블도 insert 한 후
외래키가 없는 입장에서 외래키 테이블의 외래키값을 가져와서 다시 update 해야함
(복잡, 성능안좋음, 너무헷갈림-> 엥? 난 테이블 하나만 만졋는데 왜 쿼리가 얘도 수정되게 실행되지?)
객체와 테ㅔ이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조
@JoinCulmn 꼭 사용!!!
안 그러면 조인 테이블 방식을 사용함니다(둘을 조인할 중간 테이블, 새 테이블)
일대다 단방향 단점
1) 엔티티가 관리하는 외래 키가 다른 테이블에 있음
2) 연관관계 관리를 위해 추가로 update SQL이 실행됨
-> 일대다 단방향보다는 다대일 양방향 매핑을 사용하자 ^^!
일대다 양방향
다(n)에 그냥 @JoinCulmn 넣어버리면 둘 다 주인이 돼서 망함
그래서 수정 불가 상태를 만들어줘야함(읽기 전용 매핑)
@ManyToOne
@JoinColumn(name = "TEAM_ID", insertable = false, updatable = false) // 두개 false 넣어줘야함(수정 불가)
// @JoinColumn(name = "TEAM_ID") // 얘만 있으면, 얘도 주인이 돼서 망함
private Team team;
요런 식으로 하믄 댐니당 !
일대다 양방향은 공식적으로 존재는 안 하지만, 사용은 가능하다
@JoinColumn(insertable = false, updatable = false)
얘를 써서 읽기 전용 필드를 만들고 사용 가능
필요할 때가 있긴 함
-> 되도록 다대일 양방향을 사용합시다 ^_^
@OneToOne
일대일(1:1)
주 테이블 / 대상 테이블 중에 외래키 선택 가능
외래 키에 데이터베이스 유니크(UNI) 제약조건을 추가해야한당
주 테이블에 외래 키 단방향?
다대일 단방향 매핑과 똑같음! 어노테이션만 다름니다
주테이블에 외래키~
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
Locker 테이블
@Entity
public class Locker {
@Id @GeneratedValue
private Long id;
private String name;
}
다대일 단방향 매핑과 유사함니다
외래 키가 있는 곳이 연관관계 주인이고, 반대편은 mappedBy 사용해요
대상 테이블에 외래 키가 있는 단방향
ㄴ 얘는 안대연 XXXX
ㄴ JPA에서 지원 안 됨
대상 테이블에 외래 키 양방향
내 외래키는 내가 직접 관리함니다
그래서 주인에서 가져온 객체로 관리하면 됨
1:1 관계의 경우
주로 select하는 테이블에 외래키가 있는 것이 편함니다~
Member가 Locker를 가지고 있도록 ^-^
대신 양방향을 거는 걸어야 하긴 하지만~ 그래도 뭐 어때~
주 테이블에 외래 키 ** 개발자들이 조아해용
- 객체 지향 개발자가 선호
- JPA 매핑 편리
장점) 주 테이블만 조회해도 대상 테이블에 데이터 있는지 확인 가능
단점) 값이 없으면 외래키에 null
대상 테이블에 외래 키
- 전통적인 DB 개발자 선호
장점) 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할때 테이블 구조 유지
단점) 어쩔 수 없이 양방향으로 만들어야 함
프록시 기능의 한계로, 지연 로딩으로 설정해도 항상 즉시 로딩됩니다ㅠㅠ
(있는지 없는지 무조건 확인해야하기 때문)
@ManyToMany
다대다(n:m)
얘는 안써연~~쓰지마세연~~~ㅎㅎ;
관계형 데이터 베이스는 정규화된 테이블 2개로 다대다 관계 표현 불가
연결 테이블을 추가해서 일대다, 다대일 관계로 만들어야 합니다(중간다리)
그런데, 객체는 컬렉션을 사용해서 객체 2개로 다대다 가능해요
그래서 객체끼리는 다대다
DB에서는 테이블-연결테이블-테이블
@ManyToMany
@JoinTable(name = "연결테이블명")
해서 사용 가능하긴 해요...
실무에서 사용 XXXXX
연결 테이블이 단순히 연결만 하고 끝나지 않는데, 중간 추가 정보를 넣을 수는 없음
중간 테이블 때문에 쿼리도 이상하게 됨
다대다를 쓰고 싶다면?
연결 테이블을 @Entity로 만들고 (추가정보 넣기 가능)
@OneToMany / @ManyToOne 로 관계를 맺어준다(다대일, 일대다)
PK는 그냥 의미 없는 값을 쓰세요잉~
(비즈니스에 의미 없는 값)
Id가 어딘가에 종속되어있으면, 유연하게 시스템을 갈아치우기 쉽지 않음
@Id @GenarateValue ->걍 묶어서 쓰는 게 편해요
private PK
'개발공부 개발새발 > DB' 카테고리의 다른 글
JPA) 프록시란 무엇인가 (0) | 2022.11.25 |
---|---|
JPA) 상속관계 매핑 (여러 전략들과 @MappedSuperclass) (0) | 2022.11.25 |
JPA) 연관관계 매핑 (1) | 2022.11.24 |
JPA) 엔티티매핑(객체와 테이블, 필드와 컬럼, 기본 키) (0) | 2022.11.24 |
JPA) CRUD, 영속성 컨텍스트, 플러시, 준영속상태 (0) | 2022.11.24 |