요구사항 가정
회원당 무조건 하나의 락커 를 점유한다.
락커 또한 무조건 한명의 회원만 사용할 수 있다.
테이블 설계
1:1 관계가 성립해야한다.
그러나 부모 자식 관계가 성립해야하고 외래키는 존재해야한다.
JPA Entity class 설계
단 1:1로 살아있는 테이블을 만든다고 하면 1:1 연관관계 설정 (@OneToOne) 필요하다.
주 대상 테이블 || 대상 테이블에 외래키와 UNIQUE 제약조건을 건다. (그래야 1:1이 제대로 성립한다.)
FK를 회원에 둘 것인가
사물함에 둘 것인가?
나라면 이렇게 설계하겠다.
회원에 사물함 아이디를 FK로 보유한다. 엔티티 클래스에서는 연관관계 주인으로 삼는다.
테이블 설계상으로나 비즈니스 로직상으로나 사물함으로부터 회원을 조회하기보다
특정 회원의 사물함을 불러오는 것이 더 필요할 것같다.
따라서 @JoinColumn을 Member entity class 쪽에 두고
추후에 사물함으로부터 회원 조회를 자주 해야하는 상황일 때 @OneToOne(mappedBy="locker")를 걸겠다.
내가 DBA라면?
시간이 흘러서 하나의 회원이 여러 Locker 를 가지는 것으로 요구사항이 변경되면 어떻게 될까?
Member 가 자식일 때
장점
애플리케이션 성능상 member table 에 쿼리를 자주 날린다면, 비즈니스 로직과 성능상 이득이 있다.
member 관련 쿼리 하나로 락커도 제어하기 쉬워진다.
단방향 연관관계 설정만으로 비즈니스 로직이 가능하다.
단점
위처럼 요구사항 변경시 , Table 설계 변경이 불가피하다.
Locker 가 자식일 때
장점
일대다 관계로 변경시 테이블 스키마 유지 가능
요구사항 변경시, 에서 member_id 에 대한 UNIQUE 제약 조건만 삭제하면된다.
단점
따라서 JPA 상에서 Locker 를 통해 Member 정보를 불러올 수 있게끔 양방향 연관관계를 설정해야 할 것이다.
@OneToOne(mappedBy = member)
Locker 클래스 정보를 불러오기 위해 쿼리를 2개를 나눠서 날려야한다.
(SELECT column FROM Locker),
(SELECT column FROM Member)
Member class 정보만 가지고 Locker 정보를 알아낼 수 없다.
+
JPA 프록시 기능의 한계로 지연로딩 설정해도 항상 즉시 로딩처리됨.
나라면 애플리케이션 개발에 집중.
Member 를 연관관계 주인으로 설정하는 것을 선호한다.
Member.java
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "member_id")
private Long id;
@Column(name = "member_name", updatable = true, nullable = false, length = 255)
private String name;
@OneToOne
@JoinColumn(name = "locker_id", unique = true)
private Locker locker;
}
Locker.java
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Locker {
@Id @GeneratedValue
@Column(name = "locker_id")
private Long id;
@Column(name = "locker_name")
private String name;
public Locker(String name) {
this.name = name;
}
/**
* [양방향 연관관계 설정]
* Locker 로 부터 Member 조회가 자주 필요할 때만 추가하면 된다.
*/
// mapped by 걸린 곳은 조회만 가능함.
// @OneToOne(mappedBy = "locker")
// @Column(name = "member_id")
// private Member member;
}
ERD
연관관계
Java Entity class 와 RDB 의 테이블간의 매핑시 맺어진 관계를 연관 관계라고한다.
순수 Entity 객체는 테이블간 관계를 알지 못한다.
OOP 관점에서, Java Entity class 간의 상호작용이 테이블간 관계를 고려하여 일어날 수 있게 하기 위한 설정이다.
예) Member 에게 소속 팀을 설정한다. -> 해당 팀 이름이 변경된다. -> 멤버가 소속된 팀 이름 조회시 변경된 팀 이름이 조회된다.
단방향 연관관계
아래 나열된 어노테이션을 가진 객체가 '연관관계'를 단방향으로 가지고 있다고 볼 수 있다.
- ManyToOne
- OneToMany
- OneToOne
- ManyToMany
양방향 연관관계
객체간 연관관계는 '단방향' 연관관계 밖에 없다.
위 어노테이션이 양쪽에 다 붙어있을 때 단방향이 서로 매핑되어 '양방향' 연관관계가 형성된다.
그렇다면 DB는 무슨 관계를 가진 것일까?
DB는 외래키 자체가 양방향 연관관계 역할을 한다고 볼 수 있다.
외래키 하나만으로 양쪽 Table 을 모두 조작할 수 있기 때문이다.
연관관계 주인
99%는 '외래키'를 가진 쪽(Many)이 연관관계 주인이다.
문제는 양방향 연관관계일 때인데
이때는 'mappedBy' 가 가리키는 Entity 가 곧 연관관계 주인이 된다.
그래서 연관관계 주인이 되면 뭐가 다른데?
객체 생성 및 조작은 연관관계 주인에서만 가능하다.
연관관계 주인이 아닌 엔티티 클래스에서는 오로지 '조회'만 가능하다.
'JVM > JPA' 카테고리의 다른 글
[JPA] 상속관계 매핑 (0) | 2023.01.13 |
---|---|
[JPA] auto_increment 전략 IDENTITY vs SEQUENCE (0) | 2023.01.09 |
[JPA] JPA 는 왜 등장했을까? (0) | 2023.01.07 |
[JPA] API 생성시 Entity 를 반환하지 말자. (0) | 2022.12.29 |